import warnings
import numpy as np
import pandas as pd
from typing import Literal

from ..dataclass.tables import TableData, TableCollection
from ..dataclass.geoProfiles import MaterialTable
from ..geocal import loessCal, liquidationCal
from ..geocal.dataResource import loadData
from ..dataclass.terminologies import GeoMaterialProps, Units, GeoResults, GeneralProps
from ..pipeline.portTypes import PortType, PortTypeHint
from ..pipeline.pipeline import PipeModule, status_manage, Port, RangeModel
from ..connectors.publicApiConnector import query_seismic_params_by_longitude_latitude
from ..geocal.general import get_seismic_design_params
from ..dataclass.results import UnitResult, SingleResult
from ..geocal.waterSoilCorrosion import evaluation_by_env_type, concrete_corrosion_by_Cl, concrete_corrosion_by_PH
from ..dataclass import GDIDataQualityWarning

SoilClassification = loadData.load_soil_classification()


@status_manage
class RecentlyDepositedLoess(PipeModule):
    """
    新近堆积黄土计算判别
    """

    def __init__(self,
                 mname: str = "RecentlyDepositedLoess",
                 auto_run: bool = True,
                 stat_tables: PortTypeHint.TableCollection | None = None,
                 stat_table_name: str | None = None) -> None:
        super().__init__(mname=mname, auto_run=auto_run)

        self._ports_in = {"InputStatTables": Port(PortType.TableCollection, data=stat_tables, pdoc="输入数理统计表")}
        self._ports_out = {"OutputTableData": Port(PortType.TableData, pdoc="输出表数据")}

        self.stat_table_name = stat_table_name

    @property
    def InputStatTables(self) -> None:
        raise AttributeError("Property 'InputStatTables' is write-only.")

    @InputStatTables.setter
    def InputStatTables(self, value: PortTypeHint.TableCollection | None) -> None:
        self._ports_in["InputStatTables"].data = value

    @property
    def OutputTableData(self) -> PortTypeHint.TableData | None:
        return self._ports_out["OutputTableData"].data

    def set_cal_params(self, reset: bool = True) -> dict[str, RangeModel] | None:
        stat_tables: PortTypeHint.TableCollection | None = self._ports_in["InputStatTables"].data

        if stat_tables is None:
            stat_table_name_choice = None
        else:
            stat_table_name_choice = stat_tables.table_titles
            if reset:
                self.stat_table_name = stat_table_name_choice[0]

        values_range = {
            "stat_table_name": RangeModel(vtype="str", choices=stat_table_name_choice, default=self.stat_table_name,
                                          title="常规试验统计表")}

        return values_range

    @staticmethod
    def get_recently_calc_data(stat_table):
        """
        获取新近黄土堆积计算所需的数据
        """
        layer_number_list = []  # 地层编号 [-]
        layer_name_list = []  # 地层名称 [-]
        void_ratio_list = []  # 层的平均孔隙比 [-]
        compression_factor_list = []  # 层的压缩系数 [MPa^-1]
        # 层的压缩系数取（MAX{0-100kPa压力段下压缩系数的平均值，50-150kPa压力段下压缩系数的平均值}）
        unit_weight_list = []  # 层的平均重度 [kN/m^3]
        natural_water_content_list = []  # 层的平均天然含水量 [%]

        table_titles = stat_table.field_titles

        error_count = 0
        if ("层号" not in table_titles) or ("岩土名称" not in table_titles) or ("取样编号" not in table_titles) or (
                "天然孔隙比" not in table_titles) or (
                "压缩系数 α0-0.1MPa" not in table_titles) or ("压缩系数 α0.05-0.15MPa" not in table_titles) or (
                "天然密度" not in table_titles) or ("含水率" not in table_titles):
            error_count += 1
            return {'error_count': error_count,
                    'void_ratio_list': [],
                    'compression_factor_list': [],
                    'unit_weight_list': [],
                    'natural_water_content_list': []
                    }

        layer_number_name = stat_table.title_to_name["层号"]
        layer_name_name = stat_table.title_to_name["岩土名称"]
        sample_number_name = stat_table.title_to_name["取样编号"]
        void_ratio_name = stat_table.title_to_name["天然孔隙比"]
        compression_factor100_name = stat_table.title_to_name["压缩系数 α0-0.1MPa"]
        compression_factor150_name = stat_table.title_to_name["压缩系数 α0.05-0.15MPa"]
        density_name = stat_table.title_to_name["天然密度"]
        natural_water_content_name = stat_table.title_to_name["含水率"]
        #
        layer_number = stat_table[layer_number_name]
        layer_name = stat_table[layer_name_name]
        sample_number = stat_table[sample_number_name]
        void_ratio = stat_table[void_ratio_name]
        compression_factor100 = stat_table[compression_factor100_name]
        compression_factor150 = stat_table[compression_factor150_name]
        density = stat_table[density_name]
        natural_water_content = stat_table[natural_water_content_name]

        if not (len(layer_number) == len(layer_name) == len(sample_number) == len(void_ratio) == len(
                compression_factor100) == len(
            compression_factor150) == len(density) == len(natural_water_content)):
            error_count += 1
            return {'error_count': error_count,
                    'void_ratio_list': [],
                    'compression_factor_list': [],
                    'unit_weight_list': [],
                    'natural_water_content_list': []
                    }

        # 获取所有"算术平均值"对应的索引
        avg_indices = []
        for i, sample in enumerate(sample_number):
            if sample == "算数平均值":
                avg_indices.append(i)

        # 只保留"算术平均值"对应的数据
        filtered_layer_number = [layer_number[i] for i in avg_indices]
        filtered_layer_name = [layer_name[i] for i in avg_indices]
        filtered_void_ratio = [void_ratio[i] for i in avg_indices]
        filtered_compression_factor100 = [compression_factor100[i] for i in avg_indices]
        filtered_compression_factor150 = [compression_factor150[i] for i in avg_indices]
        filtered_density = [density[i] for i in avg_indices]
        filtered_natural_water_content = [natural_water_content[i] for i in avg_indices]

        # 过滤空值
        valid_indices = []
        for i in range(len(filtered_void_ratio)):
            if (i < len(filtered_void_ratio) and i < len(filtered_compression_factor100) and
                    i < len(filtered_compression_factor150) and i < len(filtered_density) and
                    i < len(filtered_natural_water_content) and
                    filtered_void_ratio[i] != '' and filtered_compression_factor100[i] != '' and
                    filtered_compression_factor150[i] != '' and filtered_density[i] != '' and
                    filtered_natural_water_content[i] != ''):
                valid_indices.append(i)

        # 使用有效索引筛选数据
        filtered_layer_number = [filtered_layer_number[i] for i in valid_indices if i < len(filtered_layer_number)]
        filtered_layer_name = [filtered_layer_name[i] for i in valid_indices if i < len(filtered_layer_name)]

        # 转换为float类型
        filtered_void_ratio = [float(filtered_void_ratio[i]) for i in valid_indices if i < len(filtered_void_ratio)]
        filtered_compression_factor100 = [float(filtered_compression_factor100[i]) for i in valid_indices if
                                          i < len(filtered_compression_factor100)]
        filtered_compression_factor150 = [float(filtered_compression_factor150[i]) for i in valid_indices if
                                          i < len(filtered_compression_factor150)]
        filtered_density = [float(filtered_density[i]) for i in valid_indices if i < len(filtered_density)]
        filtered_natural_water_content = [float(filtered_natural_water_content[i]) for i in valid_indices if
                                          i < len(filtered_natural_water_content)]

        # 计算压缩系数（取两个压力段中的最大值）
        filtered_compression_factor = []
        for i in range(len(filtered_compression_factor100)):
            cf100 = filtered_compression_factor100[i]
            cf150 = filtered_compression_factor150[i]
            filtered_compression_factor.append(max(cf100, cf150))

        # 将过滤后的数据添加到结果列表中
        layer_number_list.extend(filtered_layer_number)
        layer_name_list.extend(filtered_layer_name)
        void_ratio_list.extend(filtered_void_ratio)
        compression_factor_list.extend(filtered_compression_factor)
        # 密度(g/cm³)转换为重度(kN/m³)：重度 = 密度 × 9.81
        converted_unit_weight = [density_value * 9.81 for density_value in filtered_density]
        unit_weight_list.extend(converted_unit_weight)
        natural_water_content_list.extend(filtered_natural_water_content)

        # layer_number_list = ["2-1", "4-1"]
        # layer_name_list = ["黄土1", "黄土2"]
        # void_ratio_list = [0.6, 0.8]
        # compression_factor_list = [0.4, 0.5]
        # unit_weight_list = [18.0, 19.0]
        # natural_water_content_list = [15.0, 16.0]

        data_dict = {'error_count': error_count,
                     'layer_number_list': layer_number_list,
                     'layer_name_list': layer_name_list,
                     'void_ratio_list': void_ratio_list,
                     'compression_factor_list': compression_factor_list,
                     'unit_weight_list': unit_weight_list,
                     'natural_water_content_list': natural_water_content_list}

        return data_dict

    @staticmethod
    def recently_calc(void_ratio_list, compression_factor_list, unit_weight_list, natural_water_content_list):
        """
        新近堆积黄土计算
        """
        r_list = []  # R的数值
        result_list = []  # 判别结果，"是"或"否"
        result_str_list = []  # 判别结果文字，"是新近堆积黄土"或"非新近堆积黄土"
        for i in range(0, len(void_ratio_list)):
            e = void_ratio_list[i]
            a = compression_factor_list[i]
            gamma = unit_weight_list[i]
            omega = natural_water_content_list[i]

            r, result, result_str = loessCal.recent_depos_loess_justify(e=e, a=a, gamma=gamma, omega=omega)

            r_list.append(r)

            if result:
                result_list.append("是")
            else:
                result_list.append("否")

            result_str_list.append(result_str)

        result_dic = {'r_list': r_list,
                      'result_list': result_list,
                      'result_str_list': result_str_list}

        return result_dic

    def execute(self) -> PortTypeHint.TableData | None:
        stat_tables: PortTypeHint.TableCollection | None = self._ports_in["InputStatTables"].data

        if stat_tables is None or len(stat_tables) == 0:
            self._ports_out["OutputTableData"].data = None
            return None

        # 获取统计表名默认值
        if self.stat_table_name is None:
            self.set_cal_params(reset=True)

        stat_table = stat_tables.get_table(self.stat_table_name)

        # 获取数据
        data_dict = RecentlyDepositedLoess.get_recently_calc_data(stat_table)

        if data_dict['error_count'] > 0:
            self._ports_out["OutputTableData"].data = None
            return None

        layer_number_list = data_dict['layer_number_list']
        layer_name_list = data_dict['layer_name_list']
        void_ratio_list = data_dict['void_ratio_list']
        compression_factor_list = data_dict['compression_factor_list']
        unit_weight_list = data_dict['unit_weight_list']
        natural_water_content_list = data_dict['natural_water_content_list']

        # 计算
        result_dic = RecentlyDepositedLoess.recently_calc(void_ratio_list=void_ratio_list,
                                                          compression_factor_list=compression_factor_list,
                                                          unit_weight_list=unit_weight_list,
                                                          natural_water_content_list=natural_water_content_list
                                                          )
        r_list = result_dic['r_list']
        result_list = result_dic['result_list']
        result_str_list = result_dic['result_str_list']

        '''
        if material_table.materials_table[GeoMaterialProps.LayerNumber] is not None:
            layer_number_list = material_table.materials_table[GeoMaterialProps.LayerNumber]
        else:
            return None
        if material_table.materials_table[GeoMaterialProps.MaterialName] is not None:
            layer_name_list = material_table.materials_table[GeoMaterialProps.MaterialName]
        else:
            return None
        if material_table.materials_table[GeoMaterialProps.VoidRatio] is not None:
            void_ratio_list = material_table.materials_table[GeoMaterialProps.VoidRatio]
        else:
            return None
        if material_table.materials_table[GeoMaterialProps.CompressionFactor] is not None:
            compression_factor_list = material_table.materials_table[GeoMaterialProps.CompressionFactor]
        else:
            return None
        if material_table.materials_table[GeoMaterialProps.UnitWeight] is not None:
            unit_weight_list = material_table.materials_table[GeoMaterialProps.UnitWeight]
        else:
            return None
        if material_table.materials_table[GeoMaterialProps.NaturalWaterContent] is not None:
            natural_water_content_list = material_table.materials_table[GeoMaterialProps.NaturalWaterContent]
        else:
            return None

        lists = [layer_number_list, layer_name_list, void_ratio_list, compression_factor_list, unit_weight_list,
                 natural_water_content_list]
        lengths = {len(lst) for lst in lists}
        if len(lengths) != 1:  # 判断每个list的长度是否相等，不相等返回None
            return None

        if None in layer_number_list:
            return None
        if None in layer_name_list:
            return None
        if None in void_ratio_list:
            return None
        if None in compression_factor_list:
            return None
        if None in unit_weight_list:
            return None
        if None in natural_water_content_list:
            return None

        if any(math.isnan(item) for item in void_ratio_list):
            return None
        if any(math.isnan(item) for item in compression_factor_list):
            return None
        if any(math.isnan(item) for item in unit_weight_list):
            return None
        if any(math.isnan(item) for item in natural_water_content_list):
            return None

        all_results = TableResult(result=result_table_df,
                                  units=[Units.null, Units.null, Units.null, Units.MPa_i,
                                         Units.kN_m3, Units.percent, Units.null, Units.null, Units.null],
                                  ch_names=["地层编号", "地层名称", "孔隙比e", "压缩系数a", "重度γ", "天然含水量ω", "R",
                                            "R＞R0 = -154.8", "判别结果"]        

        self._ports_out["OutputResults"].data = all_results

        return all_results
        result_table = {
            "LayerNumber": ["2-1", "4-1", "6-1", "8-1"],
            "MaterialName": ["黄土1", "黄土2", "黄土3", "黄土4"],
            "VoidRatio": [0.6, 0.8, 0.7, 0.9],
            "CompressionFactor": [0.4, 0.5, 0.45, 0.55],
            "UnitWeight": [18.0, 19.0, 18.5, 19.5],
            "NaturalWaterContent": [15.0, 16.0, 15.5, 16.5]
        }
        '''

        result_table_df = pd.DataFrame({GeoMaterialProps.LayerNumber: layer_number_list,
                                        GeoMaterialProps.LayerName: layer_name_list,
                                        GeoMaterialProps.VoidRatio: void_ratio_list,
                                        GeoMaterialProps.CompressionFactor: compression_factor_list,
                                        GeoMaterialProps.UnitWeight: unit_weight_list,
                                        GeoMaterialProps.NaturalWaterContent: natural_water_content_list,
                                        "recentValue": r_list,
                                        "recentValueJustify": result_list,
                                        "recentValueJustifyResult": result_str_list})

        output = TableData(
            result_table_df,
            name="RecentlyTable",
            title="新近堆积黄土判别表"
        )

        output.update_field_metadata(
            field_name=GeoMaterialProps.LayerNumber,
            title="地层编号",
            unit=Units.UNITLESS
        )

        output.update_field_metadata(
            field_name=GeoMaterialProps.LayerName,
            title="地层名称",
            unit=Units.UNITLESS
        )

        output.update_field_metadata(
            field_name=GeoMaterialProps.VoidRatio,
            title="孔隙比e",
            unit=Units.UNITLESS
        )

        output.update_field_metadata(
            field_name=GeoMaterialProps.CompressionFactor,
            title="压缩系数a",
            unit=Units.MPa_i1
        )

        output.update_field_metadata(
            field_name=GeoMaterialProps.UnitWeight,
            title="重度γ",
            unit=Units.kN_m3
        )

        output.update_field_metadata(
            field_name=GeoMaterialProps.NaturalWaterContent,
            title="天然含水量ω",
            unit=Units.PERCENT
        )

        output.update_field_metadata(
            field_name="recentValue",
            title="R",
            unit=Units.UNITLESS
        )

        output.update_field_metadata(
            field_name="recentValueJustify",
            title="R＞R0 = -154.8",
            unit=Units.UNITLESS
        )

        output.update_field_metadata(
            field_name="recentValueJustifyResult",
            title="判别结果",
            unit=Units.UNITLESS
        )

        self._ports_out["OutputTableData"].data = output
        return output


@status_manage
class Collapsibility(PipeModule):
    """
    湿陷性计算判别

    参数：

    area_id (int): 用户在前端选择相应地区，转换为int型，1-陇西地区；2-陇东、陕北、晋西地区；3-关中地区；4-其它地区 [-]

    f_bottom_elev (float | None): 用户在前端输入的基础底标高 [m]，如果用户没有输入此项，程序自动取地表下1.5米为基础底标高

    计算规则：
    - 自重湿陷量：从天然地面（孔口标高）起算，反映土体在自重作用下的湿陷变形
    - 湿陷量：从基础底面标高起算，反映基础荷载作用下的湿陷变形

    样品表格式：

    {
        MaterialProp.MaterialID: [18, 19, 20],  # 样品ID
        MaterialProp.LayerNumber: ["qy1", "qy2", "qy3"],  # 样品名称
        MaterialProp.GravityCollapseFactor: [0.004, 0.026, 0.015],  # 自重湿陷系数
        MaterialProp.CollapseFactor: [0.042, 0.038, 0.034]  # 湿陷系数
    }

    units=[null, null, null, null]
    """

    def __init__(self,
                 mname: str = "Collapsibility",
                 auto_run: bool = True,
                 tables: PortTypeHint.TableCollection | None = None,  # 地层表、常规试验表、勘探点表
                 building_tables: PortTypeHint.TableCollection | None = None,  # 建筑物工程概况表
                 # profiles: PortTypeHint.MultiProfile1D | PortTypeHint.Profile1D | None = None,
                 # f_bottom_elev: float | None = None,
                 area: Literal["陇西地区", "陇东、陕北、晋西地区", "关中地区", "其它地区"] = "陇西地区") -> None:
        super().__init__(mname=mname, auto_run=auto_run)

        self._ports_in = {"InputTables": Port(PortType.TableCollection,
                                              data=tables, pdoc="输入地层表、常规试验表、勘探点表"),
                          "InputBuildingTables": Port(PortType.TableCollection,
                                                      data=building_tables, pdoc="输入建筑物工程概况表")}
        self._ports_out = {"OutputTableCollection": Port(PortType.TableCollection, pdoc="输出数据表集合")}

        # self.f_bottom_elev = f_bottom_elev
        self.area = area

    @property
    def InputTables(self) -> None:
        raise AttributeError("Property 'InputTables' is write-only.")

    @InputTables.setter
    def InputTables(self, value: PortTypeHint.TableCollection | None) -> None:
        self._ports_in["InputTables"].data = value

    @property
    def InputBuildingTables(self) -> None:
        raise AttributeError("Property 'InputBuildingTables' is write-only.")

    @InputBuildingTables.setter
    def InputBuildingTables(self, value: PortTypeHint.TableCollection | None) -> None:
        self._ports_in["InputBuildingTables"].data = value

    @property
    def OutputTableCollection(self) -> PortTypeHint.TableCollection | None:
        return self._ports_out["OutputTableCollection"].data

    def set_cal_params(self, reset: bool = True) -> dict[str, RangeModel] | None:
        # layer_tables: PortTypeHint.TableCollection | None = self._ports_in["InputLayerTables"].data
        # normal_test_tables: PortTypeHint.TableCollection | None = self._ports_in["InputNormalTestTables"].data
        #
        # if layer_tables is not None:
        #     layer_table = layer_tables["地层表"]
        #
        # if normal_test_tables is not None:
        #     normal_test_table = normal_test_tables["常规试验表"]

        area_choice = ("陇西地区", "陇东、陕北、晋西地区", "关中地区", "其它地区")
        if reset:
            self.area = area_choice[0]

        values_range = {"area": RangeModel(vtype="str", choices=area_choice,
                                           default=self.area, title="湿陷性黄土工程地质分区")}

        return values_range

    @staticmethod
    def get_profiles(layer_table, bore_table, layer_table_title_to_name,
                     bore_table_title_to_name, to_mat_table) -> PortTypeHint.MultiProfile1D:
        bore_id_bore_table_column = bore_table_title_to_name["勘探点编号"]
        top_column = bore_table_title_to_name["地面高程"]
        bore_id_layer_table_column = layer_table_title_to_name["勘探点编号"]
        layer_bot_depth_column = layer_table_title_to_name["层底深度"]

        prof_data = {}

        for key in to_mat_table.keys():
            cur_bore_id = key
            cur_top = None
            cur_layer_bot_depth = []

            for _, row in bore_table.iterrows():
                if row[bore_id_bore_table_column] == cur_bore_id:
                    cur_top = float(row[top_column])
                    break

            for _, row in layer_table.iterrows():
                if row[bore_id_layer_table_column] == cur_bore_id:
                    cur_layer_bot_depth.append(float(row[layer_bot_depth_column]))

            cur_mat_id = list(range(len(cur_layer_bot_depth)))

            prof_data[cur_bore_id] = {'top': cur_top, 'layers_depth': cur_layer_bot_depth, 'materials_id': cur_mat_id}

        for item in prof_data.items():
            print(item)

        profiles = PortTypeHint.MultiProfile1D()
        for bore, bore_data in prof_data.items():
            print(bore)
            print(to_mat_table[bore]['samples_id'])
            profile = PortTypeHint.Profile1D(top=bore_data['top'], layers_depth=bore_data['layers_depth'],
                                             materials_id=bore_data['materials_id'], pnum=bore,
                                             samples_depth=to_mat_table[bore]['samples_depth'],
                                             samples_id=to_mat_table[bore]['samples_id'],
                                             isamples_id=[215],
                                             isamples_top_depth=[1.0],
                                             isamples_length=[0.5])
            profiles.add_profile(profile)

        # profiles.remove_profile("ZK1")
        # profiles.remove_profile('ZK3')
        # profiles.remove_profile('ZK5')
        # profiles.remove_profile('ZK7')
        # profiles.remove_profile('TJ1')
        # profiles.remove_profile('TJ2')
        # profiles.remove_profile('TJ3')
        # profiles.remove_profile('TJ4')

        # tmp = 'TJ4'
        # print(profiles.get_profile(tmp).top)
        # print(profiles.get_profile(tmp).layers_depth)
        # print(profiles.get_profile(tmp).materials_id)
        # print(profiles.get_profile(tmp).pnum)
        # print(profiles.get_profile(tmp).samples_depth)
        # print(profiles.get_profile(tmp).samples_id)

        # profile_1 = PortTypeHint.Profile1D(top=100.0, layers_depth=[7.1, 9.6, 11.6], materials_id=[0, 1, 2],
        #                                    pnum="TJ2", samples_depth=[7.3, 8.5, 9.3], samples_id=[18, 19, 20])
        # profiles = PortTypeHint.MultiProfile1D()
        # profiles.add_profile(profile_1)

        print('profiles successful')

        return profiles

    @staticmethod
    def get_fbot_data(bore_table, building_table, bore_table_title_to_name, building_table_title_to_name, to_mat_table):
        bore_id_column = bore_table_title_to_name["勘探点编号"]
        belong_building_column = bore_table_title_to_name["所属建构筑物"]
        building_name_column = building_table_title_to_name["名称"]
        fbot_column = building_table_title_to_name["基础标高"]

        f_bot_data = {}
        for key in to_mat_table.keys():
            cur_bore_id = key
            cur_bld_name = None
            for _, row in bore_table.iterrows():
                if row[bore_id_column] == cur_bore_id:
                    cur_bld_name = row[belong_building_column]
                    break

            cur_fbot = None
            if cur_bld_name:
                for _, row in building_table.iterrows():
                    if row[building_name_column] == cur_bld_name:
                        cur_fbot = float(row[fbot_column])
                        break

            f_bot_data[cur_bore_id] = cur_fbot

        # f_bot_data = {'TJ2': 98.0}

        for item in f_bot_data.items():
            print(item)

        return f_bot_data

    @staticmethod
    def get_fbot_elev(profile, f_bot_data):
        bore_id = profile.pnum
        bore_top = profile.top

        if (bore_id not in f_bot_data) or (bore_id in f_bot_data and f_bot_data[bore_id] is None):
            f_bottom_elev = bore_top - 1.5
            print(f"钻孔{bore_id}使用默认基底标高: {f_bottom_elev} (孔口标高{bore_top} - 1.5m)")
        else:
            f_bottom_elev = f_bot_data[bore_id]
            print(f"钻孔{bore_id}使用指定基底标高: {f_bottom_elev}")

        return f_bottom_elev

    @staticmethod
    def get_sample_table(normal_test_table, normal_test_table_title_to_name):
        bore_id_column = normal_test_table_title_to_name["勘探点编号"]
        sample_id_column = normal_test_table_title_to_name["取样编号"]
        sample_top_depth_column = normal_test_table_title_to_name["取样顶深度"]
        sample_length_column = normal_test_table_title_to_name["取样长度"]
        sw_coll_coe_column = normal_test_table_title_to_name["自重湿陷系数"]
        coll_coe_column = normal_test_table_title_to_name["湿陷系数δs"]

        bore_id_unique = list(set(normal_test_table[bore_id_column]))

        all_bore_id = []
        all_sample_id = []
        all_sample_top_depth = []
        all_sample_length = []
        all_sw_coll_coe = []
        all_coll_coe = []
        all_arti_id = []
        arti_id = 100
        for i in range(len(bore_id_unique)):
            loop_bore_id = bore_id_unique[i]
            sample_data_cur_bore = normal_test_table[normal_test_table[bore_id_column] == loop_bore_id]

            for _, row in sample_data_cur_bore.iterrows():
                if (row[bore_id_column] != '' and
                        row[sample_id_column] != '' and
                        row[sample_top_depth_column] != '' and
                        row[sw_coll_coe_column] != '' and
                        row[coll_coe_column] != ''):
                    all_bore_id.append(str(row[bore_id_column]))
                    all_sample_id.append(str(row[sample_id_column]))  ##
                    all_sample_top_depth.append(float(row[sample_top_depth_column]))
                    if row[sample_length_column] == '':
                        all_sample_length.append(0.2)
                    else:
                        all_sample_length.append(row[sample_length_column])
                    all_sw_coll_coe.append(float(row[sw_coll_coe_column]))  ##
                    all_coll_coe.append(float(row[coll_coe_column]))  ##
                    arti_id += 1
                    all_arti_id.append(arti_id)  ##

        # print(all_bore_id)
        # print(all_sample_id)
        print(all_sample_top_depth)
        print(all_sample_length)
        # print(all_sw_coll_coe)
        # print(all_coll_coe)
        # print(all_arti_id)

        bore_id_yes_unique = list(set(all_bore_id))

        to_mat_table = {}
        for i in range(len(bore_id_yes_unique)):
            curr_bore_id = bore_id_yes_unique[i]
            indices = [index for index, bore_id in enumerate(all_bore_id) if bore_id == curr_bore_id]
            sample_top_depth = [all_sample_top_depth[index] for index in indices]
            sample_length = [all_sample_length[index] for index in indices]
            samples_id = [all_arti_id[index] for index in indices]
            samples_depth = [top + 0.5 * length for top, length in zip(sample_top_depth, sample_length)]
            to_mat_table[curr_bore_id] = {"samples_depth": samples_depth, "samples_id": samples_id}

        for item in to_mat_table.items():
            print(item)

        sample_table_df = pd.DataFrame({
            GeoMaterialProps.MaterialID: all_arti_id,
            GeoMaterialProps.LayerNumber: all_sample_id,
            GeoMaterialProps.GravityCollapseFactor: all_sw_coll_coe,
            GeoMaterialProps.CollapseFactor: all_coll_coe
        })

        # sample_table_df = pd.DataFrame({
        #     GeoMaterialProps.MaterialID: [18, 19, 20, 21, 22, 23],
        #     GeoMaterialProps.LayerNumber: ["qy1", "qy2", "qy3", "qy4", "qy5", "qy6"],
        #     GeoMaterialProps.GravityCollapseFactor: [0.004, 0.026, 0.015, 0.004, 0.026, 0.015],
        #     GeoMaterialProps.CollapseFactor: [0.042, 0.038, 0.034, 0.042, 0.038, 0.034]
        # })
        sample_table = MaterialTable(data=sample_table_df,
                                     name="样品表",
                                     # ch_names=["样品ID", "样品名称", "自重湿陷系数", "湿陷系数"]
                                     )

        print("sample_table_ok")
        return sample_table, to_mat_table

    @staticmethod
    def split_range_by_boundaries(min_val, max_val):
        """
        将给定的范围按照指定的边界值进行分段

        返回：

        list: 分段后的区间列表，其中的每个元素为[start, end]
        """
        if min_val < 0.0:
            min_val = 0.0

        if max_val < 0.0:
            max_val = 0.0

        if min_val == max_val:
            max_val += 0.1

        if min_val > max_val:
            original_min = min_val
            original_max = max_val
            min_val = original_max
            max_val = original_min

        boundaries = [5.0, 10.0, 20.0, 25.0]

        valid_boundaries = [b for b in boundaries if min_val < b < max_val]

        segments = []

        all_points = sorted([min_val] + valid_boundaries + [max_val])

        for i in range(len(all_points) - 1):
            segments.append([all_points[i], all_points[i + 1]])

        return segments

    @staticmethod
    def get_coll_info_under_found(fbot_elev, h_dict, dt_s_dict):
        """
        计算湿陷量时，需要考虑基底和代表土层的关系，此方法用于获取相关信息

        返回值示例：
        {

        'num': 5,

        101: {'dt_s': 0.026, 'rep_depth': [0.5, 1.6], 'rep_thickness_and_elev': [1.1, 10.0, 8.9]},

        102: {'dt_s': 0.013, 'rep_depth': [1.6, 2.6], 'rep_thickness_and_elev': [1.0, 8.9, 7.9]},

        103: {'dt_s': 0.016, 'rep_depth': [2.6, 3.6], 'rep_thickness_and_elev': [1.0, 7.9, 6.9]},

        104: {'dt_s': 0.045, 'rep_depth': [3.6, 4.6], 'rep_thickness_and_elev': [1.0, 6.9, 5.9]},

        105: {'dt_s': 0.038, 'rep_depth': [4.6, 5.5], 'rep_thickness_and_elev': [0.9, 5.9, 5.0]}

        }
        """
        partici_dict = {}
        for sample_id, sample_prop in h_dict.items():
            cur_rep_bot_elev = sample_prop[2]
            # 如果代表层的底标高低于基底标高，则该代表层参与计算
            if cur_rep_bot_elev < fbot_elev:
                partici_dict[sample_id] = True
            else:
                partici_dict[sample_id] = False

        h_modified_dict = {}
        for sample_id, sample_prop in h_dict.items():
            # 只操作参与判断的代表层
            if partici_dict[sample_id]:
                cur_rep_top_elev = sample_prop[1]
                cur_rep_bot_elev = sample_prop[2]
                # 如果基底标高在代表层内部
                # 则代表层顶标高取基底标高、代表层的底标高不变、代表厚度取基底标高减去代表层的底标高
                # 否则就取原来那个列表
                if cur_rep_bot_elev < fbot_elev < cur_rep_top_elev:
                    h_modified_dict[sample_id] = [fbot_elev - cur_rep_bot_elev, fbot_elev, cur_rep_bot_elev]
                else:
                    h_modified_dict[sample_id] = h_dict[sample_id]

        # 相对于基底的深度
        depth_modified_dict = {}
        for sample_id, sample_prop in h_modified_dict.items():
            cur_rep_top_elev = sample_prop[1]
            cur_rep_bot_elev = sample_prop[2]
            cur_depth_start = fbot_elev - cur_rep_top_elev
            cur_depth_end = fbot_elev - cur_rep_bot_elev
            depth_modified_dict[sample_id] = [cur_depth_start, cur_depth_end]

        dt_s_used_dict = {}
        for sample_id in h_modified_dict.keys():
            if sample_id in dt_s_dict:
                dt_s_used_dict[sample_id] = dt_s_dict[sample_id]
            else:
                dt_s_used_dict[sample_id] = 0.0

        num = len(h_modified_dict)

        result_dict = {}
        result_dict["num"] = num  # 使用的代表土层数量
        for sample_id in h_modified_dict.keys():
            result_dict[sample_id] = {
                "rep_thickness_and_elev": h_modified_dict[sample_id],
                "rep_depth": depth_modified_dict[sample_id],
                "dt_s": dt_s_used_dict[sample_id]
            }

        return result_dict

    @staticmethod
    def get_coll_calc_paras_under_found(area_id, is_gravity_coll, coll_info_under_found):
        result_dict = {}
        count = 1
        for key in coll_info_under_found:
            if key == "num":
                continue
            if "rep_depth" in coll_info_under_found[key]:
                cur_dt_s = coll_info_under_found[key]["dt_s"]
                cur_rep_depth_top = coll_info_under_found[key]["rep_depth"][0]
                cur_rep_depth_bot = coll_info_under_found[key]["rep_depth"][1]
                cur_rep_thickness = coll_info_under_found[key]["rep_thickness_and_elev"][0]
                cur_rep_top_elev = coll_info_under_found[key]["rep_thickness_and_elev"][1]
                cur_rep_bot_elev = coll_info_under_found[key]["rep_thickness_and_elev"][2]
                rep_depth_segments = Collapsibility.split_range_by_boundaries(cur_rep_depth_top, cur_rep_depth_bot)
                for rep_depth_seg in rep_depth_segments:
                    seg_rep_depth_top = rep_depth_seg[0]
                    seg_rep_depth_bot = rep_depth_seg[1]
                    seg_rep_thickness = seg_rep_depth_bot - seg_rep_depth_top
                    mid_depth = (seg_rep_depth_top + seg_rep_depth_bot) / 2.0
                    seg_alpha, seg_beta = loessCal.get_alpha_beta(area_id=area_id, is_gravity_coll=is_gravity_coll,
                                                                  depth_from_fbot=mid_depth)
                    result_dict[count] = {
                        "sample_id": key,
                        "rep_thickness": seg_rep_thickness,
                        "alpha": seg_alpha,
                        "beta": seg_beta,
                        "dt_s": cur_dt_s
                    }
                    count += 1
        result_dict["num"] = len(result_dict)

        return result_dict

    def execute(self) -> PortTypeHint.TableCollection | None:
        tables: PortTypeHint.TableCollection | None = self._ports_in["InputTables"].data
        building_tables: PortTypeHint.TableCollection | None = self._ports_in["InputBuildingTables"].data

        if not tables or not building_tables:
            self._ports_out["OutputTableCollection"].data = None
            return None

        # 获取工程地质分区的默认值
        if self.area is None:
            self.set_cal_params(reset=True)

        # 根据工程地质分区获取其编号
        if self.area == "陇西地区":
            area_id = 1
        elif self.area == "陇东、陕北、晋西地区":
            area_id = 2
        elif self.area == "关中地区":
            area_id = 3
        else:
            area_id = 4

        layer_table = tables.get_table("地层表")
        layer_table_title_to_name = layer_table.title_to_name
        print(layer_table_title_to_name)

        normal_test_table = tables.get_table("常规试验表")
        normal_test_table_title_to_name = normal_test_table.title_to_name
        print(normal_test_table_title_to_name)

        bore_table = tables.get_table("勘探点表")
        bore_table_title_to_name = bore_table.title_to_name
        print(bore_table_title_to_name)

        building_table = building_tables.get_table("建筑物工程概况表")
        building_table_title_to_name = building_table.title_to_name
        print(building_table_title_to_name)

        sample_table, to_mat_table = Collapsibility.get_sample_table(  # 获取样品表
            normal_test_table=normal_test_table,
            normal_test_table_title_to_name=normal_test_table_title_to_name)

        # 所选钻孔、所有样品
        sample_id_list = sample_table.index.tolist()

        # 所选钻孔，湿陷系数、样品名称
        dt_s_dict = {}
        sample_name_dict = {}
        for i in range(len(sample_id_list)):
            properties = sample_table.get_material(sample_id_list[i])
            dt_s_dict[sample_id_list[i]] = properties[GeoMaterialProps.CollapseFactor]
            sample_name_dict[sample_id_list[i]] = properties[GeoMaterialProps.LayerNumber]

        f_bot_data = Collapsibility.get_fbot_data(  # 获取基底数据
            bore_table=bore_table, building_table=building_table,
            bore_table_title_to_name=bore_table_title_to_name,
            building_table_title_to_name=building_table_title_to_name,
            to_mat_table=to_mat_table)

        profiles = Collapsibility.get_profiles(  # 获取一维剖面集合
            layer_table=layer_table, bore_table=bore_table,
            layer_table_title_to_name=layer_table_title_to_name,
            bore_table_title_to_name=bore_table_title_to_name,
            to_mat_table=to_mat_table)

        bore_id_surf_mlist = []
        bore_id_found_mlist = []
        sample_show_id_surf_mlist = []
        sample_show_id_found_mlist = []
        dt_zs_mlist = []
        h_surf_mlist = []  # 自重湿陷量计算的厚度列表（自地面）
        h_found_mlist = []  # 湿陷量计算的厚度列表（自基础）
        delta_zs_list_mlist = []
        dt_s_mlist = []
        alpha_mlist = []
        beta_mlist = []
        delta_s_list_mlist = []
        bore_id_slist = []
        bore_top_slist = []
        fbot_elev_slist = []
        beta0_slist = []
        delta_zs_slist = []
        is_gravity_coll_str_slist = []
        delta_s_slist = []
        coll_class_slist = []

        for profile in profiles:
            bore_id = profile.pnum
            bore_top = profile.top
            beta0 = loessCal.get_beta0(area_id=area_id)  # 因地区土质而异的修正系数

            # 计算用的基底标高，如果是空值则取基底标高为孔口标高下 1.5 m
            f_bottom_elev = Collapsibility.get_fbot_elev(profile=profile, f_bot_data=f_bot_data)

            # 自重湿陷量计算，从天然地面起算，取完整剖面
            surf_profile = profile

            # 当前钻孔天然地面以下的样品 ID
            if surf_profile.samples_depth is None:
                continue
            elif len(surf_profile.samples_depth) == 0:  # samples_depth 为空列表
                print(f"该钻孔中没有样品，跳过")
                continue
            else:
                sample_id_surf = surf_profile.samples_id

            # 如果根据样品 ID 查不到其信息，就跳过该钻孔
            check_samp_id_surf_None = []
            for i in range(0, len(sample_id_surf)):
                if sample_table.get_material(sample_id_surf[i]) is None:
                    check_samp_id_surf_None.append(None)
            if None in check_samp_id_surf_None:
                continue

            # 当前钻孔中样品的数量
            n_sample_surf = len(sample_id_surf)

            # 当前钻孔中样品的自重湿陷系数
            dt_zs = []
            for i in range(0, len(sample_id_surf)):
                cur_props = sample_table.get_material(sample_id_surf[i])
                cur_dt_zs = cur_props[GeoMaterialProps.GravityCollapseFactor]
                if cur_dt_zs is None:
                    dt_zs.append(float(0.0))
                else:
                    dt_zs.append(float(cur_dt_zs))

            # 自重湿陷量计算用的代表厚度、顶底高程（从天然地面起算）
            try:
                h_dict_surf = surf_profile.cal_samples_thickness()
                if h_dict_surf is None:
                    print(f"钻孔{bore_id}的自重湿陷量厚度计算结果为None，跳过")
                    continue
            except Exception as e:
                print(f"钻孔{bore_id}计算自重湿陷量厚度时出错: {e}")
                continue

            # print("==== surf_profile.samples_id ====")
            # print(surf_profile.samples_id)
            # print("==== surf_profile.samples_depth ====")
            # print(surf_profile.samples_depth)
            # print("==== surf_profile.layers_elevation ====")
            # print(surf_profile.layers_elevation)
            # print("==== h_dict_surf 计算结果 ====")
            # print(h_dict_surf)

            # 计算湿陷量的厚度（从基础底面起算）
            # try:
            #     h_dict_found = found_profile.cal_samples_thickness()
            #     if h_dict_found is None:
            #         print(f"钻孔{bore_id}的湿陷量厚度计算结果为None，跳过")
            #         continue
            # except Exception as e:
            #     print(f"钻孔{bore_id}计算湿陷量厚度时出错: {e}")
            #     # 打印更多调试信息
            #     print(f"样品深度: {found_profile.samples_depth}")
            #     print(
            #         f"样本标高: {found_profile.samples_elevation if hasattr(found_profile, 'samples_elevation') else '无样本标高'}")
            #     print(f"层位深度: {found_profile.layers_depth}")
            #     print(
            #         f"层位标高: {found_profile.layers_elevation if hasattr(found_profile, 'layers_elevation') else '无层位标高'}")
            #     continue

            # print("==== found_profile.samples_id ====")
            # print(found_profile.samples_id)
            # print("==== found_profile.samples_depth ====")
            # print(found_profile.samples_depth)
            # print("==== found_profile.layers_elevation ====")
            # print(found_profile.layers_elevation)
            # print("==== h_dict_found 计算结果 ====")
            # print(h_dict_found)

            # 自重湿陷量计算用的代表厚度（从天然地面起算）
            h_surf = []
            for i in range(0, len(sample_id_surf)):
                if sample_id_surf[i] in h_dict_surf:
                    h_surf.append(float(h_dict_surf[sample_id_surf[i]][0]) * 1000.0)
                else:  # 若样品不在从天然地面起算的范围内，使用 0.0
                    h_surf.append(0.0)

            # 湿陷量计算用的厚度（自基础起算）
            # h_found = []
            # for i in range(0, len(sample_id)):
            #     if sample_id[i] in h_dict_found:
            #         h_found.append(float(h_dict_found[sample_id[i]][0]) * 1000.0)
            #     else:
            #         # 如果样品不在从基础底面起算的范围内，使用0
            #         h_found.append(0.0)

            # 计算自重湿陷量（使用从天然地面起算的厚度）
            # 自重湿陷量反映的是土体在自重作用下的湿陷变形，应从天然地面开始计算
            delta_zs_list, delta_zs = loessCal.delta_zs_calc(n=n_sample_surf, h=h_surf, beta0=beta0, dt_zs=dt_zs)
            is_gravity_coll, is_gravity_coll_str = loessCal.coll_site_type_justify(delta_zs=delta_zs)

            # alpha = []
            # beta = []
            # for i in range(0, n):
            #     cur_alpha, cur_beta = loessCal.get_alpha_beta(area_id=area_id, is_gravity_coll=is_gravity_coll,
            #                                                   depth_from_fbot=sample_depth_from_found_bot[i])
            #     alpha.append(cur_alpha)
            #     beta.append(cur_beta)

            coll_info_under_found = Collapsibility.get_coll_info_under_found(
                fbot_elev=f_bottom_elev, h_dict=h_dict_surf, dt_s_dict=dt_s_dict)
            coll_calc_paras_under_found = Collapsibility.get_coll_calc_paras_under_found(
                area_id=area_id, is_gravity_coll=is_gravity_coll, coll_info_under_found=coll_info_under_found)

            n_sample_found = coll_calc_paras_under_found["num"]
            h_found = []
            alpha = []
            beta = []
            dt_s = []
            sample_id_found = []
            for paras_key in coll_calc_paras_under_found.keys():
                if paras_key != "num":
                    h_found.append(coll_calc_paras_under_found[paras_key]["rep_thickness"] * 1000.0)
                    alpha.append(coll_calc_paras_under_found[paras_key]["alpha"])
                    beta.append(coll_calc_paras_under_found[paras_key]["beta"])
                    dt_s.append(coll_calc_paras_under_found[paras_key]["dt_s"])
                    sample_id_found.append(coll_calc_paras_under_found[paras_key]["sample_id"])

            # 计算湿陷量（使用从基础底面起算的厚度）
            # 湿陷量反映的是基础荷载作用下的湿陷变形，应从基础底面开始计算
            delta_s_list, delta_s = loessCal.delta_s_calc(n=n_sample_found, h=h_found, alpha=alpha, beta=beta,
                                                          dt_s=dt_s)
            coll_class = loessCal.coll_class_justify(is_gravity_coll=is_gravity_coll, delta_zs=delta_zs,
                                                     delta_s=delta_s)

            # 添加元素到自重湿陷表格的样品名称列用于显示
            for i in range(0, len(sample_id_surf)):
                cur_props = sample_table.get_material(sample_id_surf[i])
                cur_show_id = cur_props[GeoMaterialProps.LayerNumber]
                sample_show_id_surf_mlist.append(cur_show_id)

            # 添加元素到湿陷表格的样品名称列用于显示
            for i in range(0, len(sample_id_found)):
                cur_props = sample_table.get_material(sample_id_found[i])
                cur_show_id = cur_props[GeoMaterialProps.LayerNumber]
                sample_show_id_found_mlist.append(cur_show_id)

            bore_id_surf_mlist.extend([bore_id for _ in range(n_sample_surf)])
            bore_id_found_mlist.extend([bore_id for _ in range(n_sample_found)])
            dt_zs_mlist.extend(dt_zs)
            h_surf_mlist.extend(h_surf)  # 自重湿陷量计算的厚度（自地面起算）
            h_found_mlist.extend(h_found)  # 湿陷量计算的厚度（自基础起算）
            delta_zs_list_mlist.extend(delta_zs_list)
            dt_s_mlist.extend(dt_s)
            alpha_mlist.extend(alpha)
            beta_mlist.extend(beta)
            delta_s_list_mlist.extend(delta_s_list)
            bore_id_slist.append(bore_id)
            bore_top_slist.append(bore_top)
            fbot_elev_slist.append(f_bottom_elev)
            beta0_slist.append(beta0)
            delta_zs_slist.append(delta_zs)
            is_gravity_coll_str_slist.append(is_gravity_coll_str)
            delta_s_slist.append(delta_s)
            coll_class_slist.append(coll_class)

        table_single_line_df = pd.DataFrame({GeoResults.ProfileNumber: bore_id_slist,
                                             "boreTopElev": bore_top_slist,
                                             "fbotElev": fbot_elev_slist,
                                             "areaCoeBeta0": beta0_slist,
                                             "totalGravityLoessValue": delta_zs_slist,
                                             "loessType": is_gravity_coll_str_slist,
                                             "totalLoessValue": delta_s_slist,
                                             "loessClass": coll_class_slist})

        table_multi_line1_df = pd.DataFrame({GeoResults.ProfileNumber: bore_id_surf_mlist,
                                             "sampleIdSurf": sample_show_id_surf_mlist,
                                             "gravityLoessCoe": dt_zs_mlist,
                                             "repThicknessSurf": h_surf_mlist,
                                             "gravityLoessValue": delta_zs_list_mlist})

        table_multi_line2_df = pd.DataFrame({GeoResults.ProfileNumber: bore_id_found_mlist,
                                             "sampleIdFound": sample_show_id_found_mlist,
                                             "loessCoe": dt_s_mlist,
                                             "repThicknessFound": h_found_mlist,
                                             "fldProbCoeAlpha": alpha_mlist,
                                             "coeBetaInLoess": beta_mlist,
                                             "loessValue": delta_s_list_mlist})

        single_line_result = TableData(table_single_line_df,
                                       name="single_line_table",
                                       title="单行结果表")
        multi_line1_result = TableData(table_multi_line1_df,
                                       name="multi_line_table1",
                                       title="多行结果表1")
        multi_line2_result = TableData(table_multi_line2_df,
                                       name="multi_line_table2",
                                       title="多行结果表2")

        single_line_result.update_field_metadata(field_name=GeoResults.ProfileNumber,
                                                 title="探井号",
                                                 unit=Units.UNITLESS)
        single_line_result.update_field_metadata(field_name="boreTopElev",
                                                 title="孔口高程",
                                                 unit=Units.m)
        single_line_result.update_field_metadata(field_name="fbotElev",
                                                 title="基底高程",
                                                 unit=Units.m)
        single_line_result.update_field_metadata(field_name="areaCoeBeta0",
                                                 title="修正系数β0",
                                                 unit=Units.UNITLESS)
        single_line_result.update_field_metadata(field_name="totalGravityLoessValue",
                                                 title="总自重湿陷量",
                                                 unit=Units.mm)
        single_line_result.update_field_metadata(field_name="loessType",
                                                 title="湿陷类型",
                                                 unit=Units.UNITLESS)
        single_line_result.update_field_metadata(field_name="totalLoessValue",
                                                 title="总湿陷量",
                                                 unit=Units.mm)
        single_line_result.update_field_metadata(field_name="loessClass",
                                                 title="湿陷等级",
                                                 unit=Units.UNITLESS)

        multi_line1_result.update_field_metadata(field_name=GeoResults.ProfileNumber,
                                                 title="探井号",
                                                 unit=Units.UNITLESS)
        multi_line1_result.update_field_metadata(field_name="sampleIdSurf",
                                                 title="土样编号",
                                                 unit=Units.UNITLESS)
        multi_line1_result.update_field_metadata(field_name="gravityLoessCoe",
                                                 title="自重湿陷系数",
                                                 unit=Units.UNITLESS)
        multi_line1_result.update_field_metadata(field_name="repThicknessSurf",
                                                 title="代表厚度",
                                                 unit=Units.mm)
        multi_line1_result.update_field_metadata(field_name="gravityLoessValue",
                                                 title="自重湿陷量",
                                                 unit=Units.mm)

        multi_line2_result.update_field_metadata(field_name=GeoResults.ProfileNumber,
                                                 title="探井号",
                                                 unit=Units.UNITLESS)
        multi_line2_result.update_field_metadata(field_name="sampleIdFound",
                                                 title="土样编号",
                                                 unit=Units.UNITLESS)
        multi_line2_result.update_field_metadata(field_name="loessCoe",
                                                 title="湿陷系数",
                                                 unit=Units.UNITLESS)
        multi_line2_result.update_field_metadata(field_name="repThicknessFound",
                                                 title="代表厚度",
                                                 unit=Units.mm)
        multi_line2_result.update_field_metadata(field_name="fldProbCoeAlpha",
                                                 title="浸水机率系数α",
                                                 unit=Units.UNITLESS)
        multi_line2_result.update_field_metadata(field_name="coeBetaInLoess",
                                                 title="修正系数β",
                                                 unit=Units.UNITLESS)
        multi_line2_result.update_field_metadata(field_name="loessValue",
                                                 title="湿陷量",
                                                 unit=Units.mm)

        output_tables = TableCollection(name="CollapsibilityTable", title="黄土湿陷性计算表")
        output_tables.add_table(single_line_result)
        output_tables.add_table(multi_line1_result)
        output_tables.add_table(multi_line2_result)

        if single_line_result.empty or multi_line1_result.empty or multi_line2_result.empty:
            self._ports_out["OutputTableCollection"].data = None
            return None

        # 输出结果表集合的数据
        print("====== 湿陷性计算：结果表集合的数据 ======")
        for name in output_tables.table_names:
            table = output_tables.get_table(name)
            print(f"\n==== 表名: {table.name}，标题: {table.title} ====")
            print(table)
        print("====== 湿陷性计算：结果表集合的数据 END ======")

        self._ports_out["OutputTableCollection"].data = output_tables
        return output_tables


@status_manage
class Liquidation(PipeModule):
    """
    液化判别

    剖面：

    Profile1D(pnum="DK2", top=12.0,
                 materials_id=[0, 1, 2],  # 地层ID
                 layers_depth=[2.2, 6.4, 20.0],
                 isamples_id=[11, 12, 13, 14, 15, 16, 17, 18, 19, 20],  # 标贯样品的ID
                 isamples_top_depth=[0.85, 2.85, 3.85, 4.85, 5.85, 6.85, 7.85, 8.85, 9.85, 10.85],
                 isamples_length=[0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
                 samples_id=[911, 912, 913, 914, 915, 916, 917, 918, 919, 920],  # 黏粒含量样品的ID
                 samples_depth=[0.7, 2.7, 3.7, 4.7, 5.7, 6.7, 7.7, 8.7, 9.7, 10.7]
                 )

    材料表：

    {
        MaterialProp.MaterialID: [0, 1, 2],  # 地层ID [-]，已经取好的地表下20米（或15米）深度范围内的
        MaterialProp.MaterialName: ["中砂", "中砂", "中砂"],  # 岩土名称 [-]
        MaterialProp.LayerNumber: ["1", "2", "5"],  # 地层编号 [-]
        MaterialProp.GeoAge: ["Q4", "Q4", "Q4"]  # 地质时代 [-]
    }
    units=[Units.null, Units.null, Units.null, Units.null, Units.percent]

    样品表：

    isamples_table_spt_df = pd.DataFrame({
        MaterialProp.MaterialID: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],  # 样品ID [-]
        MaterialProp.SPTNumber: [6, 8, 9, 10, 12, 13, 14, 15, 15, 16]  # 标贯击数的实测值 [-]，没有取None
    })
    units=[Units.null, Units.null]

    samples_table_rhoc_df = pd.DataFrame({
        MaterialProp.MaterialID: [911, 912, 913, 914, 915, 916, 917, 918, 919, 920],  # 样品ID [-]
        MaterialProp.ClayContent: [3.1, 3.2, None, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0]  # 黏粒含量 [%]，没有取None
    })
    units=[Units.null, Units.percent]

    参数：

    seismic_intensity: 抗震设防烈度，str，取值范围["6", "7", "7.5", "8", "8.5", "9"]
    6度（0.05g）取"6"
    7度（0.10g）取"7"
    7度（0.15g）取"7.5"
    8度（0.20g）取"8"
    8度（0.30g）取"8.5"
    9度（0.40g）取"9"

    is_special_bld: 是否特殊类型的建筑，bool
    特殊类型的建筑指：对液化沉陷敏感的乙类建筑

    seismic_group: 设计地震分组，int，取值范围[1, 2, 3]
    第一组取1，第二组取2，第三组取3

    anti_float_water_level: 抗浮水位高程 [m]，float

    f_bottom_elev: 基础底面高程 [m]，float
    """

    def __init__(self,
                 mname: str = "Liquidation",
                 auto_run: bool = True,
                 # profiles: PortTypeHint.Profile1D | PortTypeHint.MultiProfile1D | None = None,
                 tables: PortTypeHint.TableCollection | None = None,  # 地层表、勘探点表、标贯表、常规试验表（黏粒含量）
                 layer_order_tables: PortTypeHint.TableCollection | None = None,  # 场地地层层序
                 # layer_tables: PortTypeHint.TableCollection | None = None,  # 地层表
                 # bore_tables: PortTypeHint.TableCollection | None = None,  # 勘探点表
                 # isample_material_table_spt: PortTypeHint.MaterialTable | None = None,
                 # sample_material_table_rhoc: PortTypeHint.MaterialTable | None = None,
                 # spt_tables: PortTypeHint.TableCollection | None = None,  # 原位测试-标贯
                 # normal_test_tables: PortTypeHint.TableCollection | None = None,  # 常规试验-黏粒含量
                 liq_just_depth: Literal[20, 15] | None = 20,  # 液化判别深度
                 seismic_intensity: Literal["6度（0.05g）", "7度（0.10g）", "7度（0.15g）",
                 "8度（0.20g）", "8度（0.30g）", "9度（0.40g）"] | None = "7度（0.10g）",  # 抗震设防烈度
                 is_special_bld: bool | None = False,  # 是否特殊类型的建筑
                 seismic_group: Literal[1, 2, 3] | None = 3,  # 设计地震分组
                 anti_float_water_level: float | None = 10000.0,  # 抗浮水位高程
                 f_bottom_elev: float | None = 0.0  # 基础底面高程
                 ) -> None:
        super().__init__(mname=mname, auto_run=auto_run)

        self._ports_in = {
            "InputTables": Port(PortType.TableCollection, data=tables, pdoc="输入GDim表格"),
            "InputLayerOrderTables": Port(PortType.TableCollection, data=layer_order_tables, pdoc="输入场地地层层序")
        }
        self._ports_out = {"OutputTableCollection": Port(PortType.TableCollection, pdoc="输出计算结果表集合")}

        self.liq_just_depth = liq_just_depth
        self.seismic_intensity = seismic_intensity
        self.is_special_bld = is_special_bld
        self.seismic_group = seismic_group
        self.anti_float_water_level = anti_float_water_level
        self.f_bottom_elev = f_bottom_elev

    @property
    def InputTables(self) -> None:
        raise AttributeError("Property 'InputTables' is write-only.")

    @InputTables.setter
    def InputTables(self, value: PortTypeHint.TableCollection | None) -> None:
        self._ports_in["InputTables"].data = value

    @property
    def InputLayerOrderTables(self) -> None:
        raise AttributeError("Property 'InputLayerOrderTables' is write-only.")

    @InputLayerOrderTables.setter
    def InputLayerOrderTables(self, value: PortTypeHint.TableCollection | None) -> None:
        self._ports_in["InputLayerOrderTables"].data = value

    @property
    def OutputTableCollection(self) -> PortTypeHint.TableCollection | None:
        return self._ports_out["OutputTableCollection"].data

    def set_cal_params(self, reset: bool = True) -> dict[str, RangeModel] | None:
        # layer_tables: PortTypeHint.TableCollection | None = self._ports_in["InputLayerTables"].data
        # spt_tables: PortTypeHint.TableCollection | None = self._ports_in["InputSptTables"].data
        # normal_test_tables: PortTypeHint.TableCollection | None = self._ports_in["InputNormalTestTables"].data

        liq_just_depth_choice = (20, 15)
        # if reset:
        #     self.liq_just_depth = 20

        seismic_intensity_choice = ("6度（0.05g）", "7度（0.10g）", "7度（0.15g）",
                                    "8度（0.20g）", "8度（0.30g）", "9度（0.40g）")
        # if reset:
        #     self.seismic_intensity = "7度（0.10g）"

        # if reset:
        #     self.is_special_bld = False

        seismic_group_choice = (1, 2, 3)
        # if reset:
        #     self.seismic_group = 3

        # if reset:
        #     self.anti_float_water_level = 10000.0

        # if reset:
        #     self.f_bottom_elev = 0.0

        values_range = {
            "liq_just_depth": RangeModel(vtype="int", choices=liq_just_depth_choice, default=20,
                                         title="液化判别深度[m]"),
            "seismic_intensity": RangeModel(vtype="str", choices=seismic_intensity_choice,
                                            default="7度（0.10g）", title="抗震设防烈度"),
            "is_special_bld": RangeModel(vtype="bool", default=False, title="是否特殊类型的建筑"),
            "seismic_group": RangeModel(vtype="int", choices=seismic_group_choice, default=3,
                                        title="设计地震分组"),
            "anti_float_water_level": RangeModel(vtype="float", default=10000.0,
                                                 title="抗浮水位高程[m]"),
            "f_bottom_elev": RangeModel(vtype="float", default=0.0,
                                        title="基础底面高程[m]")}

        return values_range

    @staticmethod
    def _cal_du(profiles: PortTypeHint.MultiProfile1D,
                material_table: PortTypeHint.MaterialTable) -> dict[str, tuple[list[float] | None, list[bool] | None]]:
        """Calculate du for each profile"""
        result = {}
        all_material_names = SoilClassification["material_name"].values
        material_types = SoilClassification["for_liquidation"].values
        for profile in profiles:
            result[profile.pnum] = ([], [])
            materials_id = profile.materials_id
            all_sand_thick = 0
            all_mud_thick = 0
            for idx, material_id in enumerate(materials_id):
                material_props = material_table.get_material(material_id)
                if material_props is None:
                    result[profile.pnum] = (None, None)
                    break
                # get material type
                material_name = material_props[GeoMaterialProps.MaterialName]
                soil_idx = np.where(all_material_names == material_name)[0]
                if len(soil_idx) == 0:
                    material_type = "其他"
                else:
                    material_type = material_types[soil_idx[0]]
                # calculate du
                if idx == 0:
                    du = 0
                else:
                    du = profile.layers_depth[idx - 1] - all_sand_thick - all_mud_thick
                is_sand = False
                if material_type in ["砂土", "粉土"]:
                    all_sand_thick += profile.layers_thickness[idx]
                    is_sand = True
                elif material_type in ["淤泥", "淤泥质土"]:
                    all_mud_thick += profile.layers_thickness[idx]
                result[profile.pnum][0].append(du)
                result[profile.pnum][1].append(is_sand)
        return result

    @staticmethod
    def get_layer_type_data(layer_order_table, layer_order_table_title_to_name):
        layer_num_column = layer_order_table_title_to_name["项目土层编号"]
        layer_type_column = layer_order_table_title_to_name["岩土类名"]

        all_layer_num = layer_order_table[layer_num_column].values
        all_layer_type = layer_order_table[layer_type_column].values

        layer_type_map = {}
        for _, row in layer_order_table.iterrows():
            layer_type_map[row[layer_num_column]] = row[layer_type_column]

        layer_type_data = {"layer_type_map": layer_type_map,
                           "all_layer_num": all_layer_num,
                           "all_layer_type": all_layer_type}

        return layer_type_data

    @staticmethod
    def get_profiles(used_bore_id, layer_num_to_id, layer_table,
                     layer_table_title_to_name, bore_table, bore_table_title_to_name,
                     liq_just_depth, spt_data, rhoc_data, use_test_data=False,
                     execute_print=False) -> PortTypeHint.MultiProfile1D:
        bore_id_of_layer_column = layer_table_title_to_name["勘探点编号"]
        layer_num_column = layer_table_title_to_name["项目土层编号"]
        layer_bot_depth_column = layer_table_title_to_name["层底深度"]

        bore_id_of_bore_column = bore_table_title_to_name["勘探点编号"]
        bore_top_column = bore_table_title_to_name["地面高程"]

        profiles = PortTypeHint.MultiProfile1D()
        for i in range(len(used_bore_id)):
            loop_bore_id = used_bore_id[i]

            layer_data_cur_bore = layer_table[layer_table[bore_id_of_layer_column] == loop_bore_id]
            cur_layer_id = []
            cur_layer_bot_depth = []
            for _, row in layer_data_cur_bore.iterrows():
                cur_layer_id.append(layer_num_to_id[row[layer_num_column]])
                cur_layer_bot_depth.append(row[layer_bot_depth_column])

            cur_bore_top = bore_table.loc[bore_table[bore_id_of_bore_column] == loop_bore_id, bore_top_column].values[0]

            if execute_print:
                print("\n==profile数据")
                print(f"钻孔编号：{loop_bore_id}")
                print(f"孔口高程：{cur_bore_top}")
                print(f"地层id：{cur_layer_id}")
                print(f"层底深度：{cur_layer_bot_depth}")

            cur_profile = PortTypeHint.Profile1D()
            cur_profile.pnum = loop_bore_id
            cur_profile.top = cur_bore_top
            cur_profile.materials_id = cur_layer_id
            cur_profile.layers_depth = cur_layer_bot_depth

            cur_liq_just_elev = cur_bore_top - liq_just_depth
            cur_profile.cut_profile(cut_elev=cur_liq_just_elev, keep_below=False, inplace=True)

            if execute_print:
                print("=取20米（15）米深度范围内的部分：")
                print(f"钻孔编号：{cur_profile.pnum}")
                print(f"孔口高程：{cur_profile.top}")
                print(f"地层id：{cur_profile.materials_id}")
                print(f"层底深度：{cur_profile.layers_depth}")

            cur_isamples_id = []
            cur_isamples_top_depth = []
            cur_isamples_length = []
            for i in range(len(spt_data["all_bore_id"])):
                if spt_data["all_bore_id"][i] == loop_bore_id:
                    cur_isamples_id.append(spt_data["all_spt_arti_id"][i])
                    cur_isamples_top_depth.append(spt_data["all_top_depth"][i])
                    cur_isamples_length.append(spt_data["all_length"][i])

            cur_profile.isamples_id = cur_isamples_id
            cur_profile.isamples_top_depth = cur_isamples_top_depth
            cur_profile.isamples_length = cur_isamples_length

            cur_samples_id = []
            cur_samples_depth = []
            for i in range(len(rhoc_data["all_bore_id"])):
                if rhoc_data["all_bore_id"][i] == loop_bore_id:
                    cur_samples_id.append(rhoc_data["all_rhoc_arti_id"][i])
                    cur_samples_depth.append(rhoc_data["all_mid_depth"][i])

            cur_profile.samples_id = cur_samples_id
            cur_profile.samples_depth = cur_samples_depth

            if execute_print:
                print("=标贯数据")
                print(f"标贯样品id：{cur_profile.isamples_id}")
                print(f"标贯样品顶深度：{cur_profile.isamples_top_depth}")
                print(f"标贯样品贯入深度：{cur_profile.isamples_length}")

                print("=黏粒含量数据")
                print(f"黏粒含量样品id：{cur_profile.samples_id}")
                print(f"黏粒含量样品中点深度：{cur_profile.samples_depth}")

            if use_test_data:
                # 测试数据
                cur_profile = PortTypeHint.Profile1D(pnum="DK2", top=12.0,
                                                     materials_id=[0, 1, 2],  # 地层ID
                                                     layers_depth=[2.2, 6.4, 20.0],
                                                     isamples_id=[11, 12, 13, 14, 15, 16, 17, 18, 19, 20],  # 标贯样品的ID
                                                     isamples_top_depth=[0.85, 2.85, 3.85, 4.85, 5.85, 6.85, 7.85, 8.85,
                                                                         9.85,
                                                                         10.85],  # 0.85, 2.3276
                                                     isamples_length=[0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
                                                     samples_id=[911, 912, 913, 914, 915, 916, 918, 919, 920],
                                                     # 黏粒含量样品的ID
                                                     samples_depth=[1.0, 3.0, 4.0, 5.0, 6.0, 7.0, 9.0, 10.0, 11.0])

            profiles.add_profile(cur_profile)

        return profiles

    @staticmethod
    def get_mat_table(layer_order_table, layer_order_table_title_to_name, use_test_data=False, execute_print=False):
        layer_num_column = layer_order_table_title_to_name["项目土层编号"]
        geo_name_column = layer_order_table_title_to_name["岩土名称"]
        age_column = layer_order_table_title_to_name["地质时代"]

        all_layer_num = layer_order_table[layer_num_column].values
        all_geo_name = layer_order_table[geo_name_column].values
        all_age_init = layer_order_table[age_column].values

        layer_num_to_id = {}
        id_counter = 0
        for layer_num in all_layer_num:
            if layer_num not in layer_num_to_id:
                layer_num_to_id[layer_num] = id_counter
                id_counter += 1

        all_layer_id = []
        for layer_num in all_layer_num:
            all_layer_id.append(layer_num_to_id[layer_num])

        all_age = []
        for age in all_age_init:
            if 'Q' in str(age) and '4' in str(age):
                all_age.append("Q4")
            else:
                all_age.append("other")

        layer_material_table_df = pd.DataFrame({
            GeoMaterialProps.MaterialID: all_layer_id,  # 地层ID [-]
            GeoMaterialProps.MaterialName: all_geo_name,  # 岩土名称 [-]
            GeoMaterialProps.LayerNumber: all_layer_num,  # 地层编号 [-]
            GeoMaterialProps.GeoAge: all_age,  # 地质时代 [-]
        })

        if use_test_data:
            # 测试数据
            layer_material_table_df = pd.DataFrame({
                GeoMaterialProps.MaterialID: [0, 1, 2],  # 地层ID [-]，已经取好的地表下20米（或15米）深度范围内的
                GeoMaterialProps.MaterialName: ["中细砂", "中砂", "淤泥质粉土"],  # 岩土名称 [-]
                GeoMaterialProps.LayerNumber: ["1", "2", "5"],  # 地层编号 [-]
                GeoMaterialProps.GeoAge: ["Q4", "Q4", "Q4"],  # 地质时代 [-]
            })

        layer_material_table = MaterialTable(data=layer_material_table_df,
                                             name="地层材料表"
                                             # units=[Units.null, Units.null, Units.null, Units.null],
                                             # ch_names=None
                                             )

        mat_data = {"layer_num_to_id": layer_num_to_id,
                    "layer_material_table": layer_material_table}

        if execute_print:
            print("\n==地质时代:")
            for i, (original, processed) in enumerate(zip(all_age_init, all_age)):
                print(f"原始值: {original}, 处理后: {processed}")

            print(f"\n==地层编号\n{all_layer_id}")
            print(f"\n==岩土名称\n{all_geo_name}")

        return mat_data

    @staticmethod
    def get_spt_table(spt_table, spt_table_title_to_name, use_test_data=False):
        bore_id_column = spt_table_title_to_name["勘探点编号"]
        top_depth_column = spt_table_title_to_name["试验点顶深度"]
        length_column = spt_table_title_to_name["贯入深度"]
        spt_num_column = spt_table_title_to_name["标贯击数"]

        bore_id_unique = list(set(spt_table[bore_id_column]))

        all_bore_id = []
        all_top_depth = []
        all_length = []
        all_spt_num = []
        all_spt_arti_id = []
        spt_arti_id = 100
        for i in range(len(bore_id_unique)):
            loop_bore_id = bore_id_unique[i]
            spt_data_cur_bore = spt_table[spt_table[bore_id_column] == loop_bore_id]

            for _, row in spt_data_cur_bore.iterrows():
                if (row[bore_id_column] != '' and
                        not pd.isna(row[top_depth_column]) and
                        not pd.isna(row[length_column]) and
                        not pd.isna(row[spt_num_column])):
                    all_bore_id.append(row[bore_id_column])
                    all_top_depth.append(row[top_depth_column])
                    all_length.append(row[length_column])
                    all_spt_num.append(row[spt_num_column])
                    spt_arti_id += 1
                    all_spt_arti_id.append(spt_arti_id)

        isamples_table_spt_df = pd.DataFrame({
            GeoMaterialProps.MaterialID: all_spt_arti_id,  # 样品ID [-]
            GeoMaterialProps.SPTNumber: all_spt_num  # 标贯击数的实测值 [-]，如果没有就取None
        })

        if use_test_data:
            # 测试数据
            isamples_table_spt_df = pd.DataFrame({
                GeoMaterialProps.MaterialID: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],  # 样品ID [-]
                GeoMaterialProps.SPTNumber: [6, 8, 9, 10, 12, 13, 14, 15, 15, 16]  # 标贯击数的实测值 [-]，如果没有就取None
            })

        isample_table_spt = MaterialTable(data=isamples_table_spt_df,
                                          name="样品表-标贯"
                                          # units=[Units.null, Units.null],
                                          # ch_names=None
                                          )

        used_bore_id = list(set(all_bore_id))

        spt_data = {"isample_table_spt": isample_table_spt,
                    "all_bore_id": all_bore_id,
                    "all_top_depth": all_top_depth,
                    "all_length": all_length,
                    "all_spt_num": all_spt_num,
                    "all_spt_arti_id": all_spt_arti_id,
                    "used_bore_id": used_bore_id
                    }

        return spt_data

    @staticmethod
    def get_rhoc_table(used_bore_id, normal_test_table, normal_test_table_title_to_name, layer_type_map,
                       layer_table, layer_table_title_to_name, use_test_data=False):
        layer_num_column = normal_test_table_title_to_name["地层编号"]
        bore_id_column = normal_test_table_title_to_name["勘探点编号"]
        top_depth_column = normal_test_table_title_to_name["取样顶深度"]
        length_column = normal_test_table_title_to_name["取样长度"]
        rhoc_column = normal_test_table_title_to_name["黏粒含量"]

        print("normal_test_table添加数据之前：")
        print(normal_test_table[layer_num_column])
        print(normal_test_table[bore_id_column])
        print(normal_test_table[top_depth_column])
        print(normal_test_table[length_column])
        print(normal_test_table[rhoc_column])

        if "砂土" in layer_type_map.values():
            layer_num_column_lt = layer_table_title_to_name["项目土层编号"]
            bore_id_column_lt = layer_table_title_to_name["勘探点编号"]

            for i in range(len(used_bore_id)):
                current_bore_id = used_bore_id[i]
                current_bore_info = layer_table[layer_table[bore_id_column_lt] == current_bore_id]
                for _, row in current_bore_info.iterrows():
                    if layer_type_map[row[layer_num_column_lt]] == "砂土":
                        new_row = {
                            layer_num_column: row[layer_num_column_lt],
                            bore_id_column: current_bore_id,
                            top_depth_column: 0.1,
                            length_column: 0.2,
                            rhoc_column: 3.0
                        }
                        normal_test_table.loc[len(normal_test_table)] = new_row

            print("normal_test_table添加数据之后：")
            print(normal_test_table[layer_num_column])
            print(normal_test_table[bore_id_column])
            print(normal_test_table[top_depth_column])
            print(normal_test_table[length_column])
            print(normal_test_table[rhoc_column])

        all_bore_id = []
        all_top_depth = []
        all_length = []
        all_rhoc = []
        all_rhoc_arti_id = []
        rhoc_arti_id = 1000
        for i in range(len(used_bore_id)):
            loop_bore_id = used_bore_id[i]
            rhoc_data_cur_bore = normal_test_table[normal_test_table[bore_id_column] == loop_bore_id]

            for _, row in rhoc_data_cur_bore.iterrows():
                if (row[bore_id_column] != '' and
                        not pd.isna(row[top_depth_column]) and
                        not pd.isna(row[length_column])):
                    all_bore_id.append(row[bore_id_column])
                    all_top_depth.append(row[top_depth_column])
                    all_length.append(row[length_column])
                    if row[layer_num_column] != '' and layer_type_map[row[layer_num_column]] == "砂土" and pd.isna(
                            row[rhoc_column]):
                        all_rhoc.append(3.0)
                    elif row[layer_num_column] != '' and layer_type_map[row[layer_num_column]] == "粉土" and pd.isna(
                            row[rhoc_column]):
                        all_rhoc.append(3.0)
                    else:
                        all_rhoc.append(row[rhoc_column])
                    rhoc_arti_id += 1
                    all_rhoc_arti_id.append(rhoc_arti_id)

        # 根据rhoc的顶深度和取样长度计算其中点深度
        all_mid_depth = []
        for i in range(len(all_top_depth)):
            all_mid_depth.append(all_top_depth[i] + all_length[i] / 2)

        samples_table_rhoc_df = pd.DataFrame({
            GeoMaterialProps.MaterialID: all_rhoc_arti_id,  # 样品ID [-]
            GeoMaterialProps.ClayContent: all_rhoc  # 黏粒含量 [%]
            # 没有取None（新的没有这样做，没有就直接不取这个样本，后面rhoc往标贯上匹配的时候，匹配不上的直接取rhoc为3.0）
        })

        if use_test_data:
            # 测试数据
            samples_table_rhoc_df = pd.DataFrame({
                GeoMaterialProps.MaterialID: [914, 911, 912, 913, 918, 915, 916, 919, 920],  # 样品ID [-]
                GeoMaterialProps.ClayContent: [3.4, 3.1, 3.2, None, 3.8, 3.5, 3.6, 3.9, 4.0]  # 黏粒含量 [%]，没有取None
            })

        sample_table_rhoc = MaterialTable(data=samples_table_rhoc_df,
                                          name="样品表-黏粒含量"
                                          # units=[Units.null, Units.percent],
                                          # ch_names=None
                                          )

        rhoc_data = {"sample_table_rhoc": sample_table_rhoc,
                     "all_bore_id": all_bore_id,
                     "all_top_depth": all_top_depth,
                     "all_length": all_length,
                     "all_mid_depth": all_mid_depth,
                     "all_rhoc": all_rhoc,
                     "all_rhoc_arti_id": all_rhoc_arti_id}

        return rhoc_data

    def execute(self) -> PortTypeHint.TableCollection | None:
        # profiles: PortTypeHint.Profile1D | PortTypeHint.MultiProfile1D | None = self._ports_in[
        #     "InputProfiles"].data
        # layer_material_table: PortTypeHint.MaterialTable | None = self._ports_in["InputLayerMaterialTable"].data
        # isample_material_table_spt: PortTypeHint.MaterialTable | None = self._ports_in[
        #     "InputISampleMaterialTable_spt"].data
        # sample_material_table_rhoc: PortTypeHint.MaterialTable | None = self._ports_in[
        #     "InputSampleMaterialTable_rhoc"].data
        tables: PortTypeHint.TableCollection | None = self._ports_in["InputTables"].data
        layer_order_tables: PortTypeHint.TableCollection | None = self._ports_in["InputLayerOrderTables"].data

        if not tables or not layer_order_tables:
            self._ports_out["OutputTableCollection"].data = None
            return None

        use_test_data = False  # 是否使用测试数据
        execute_print = True  # 是否向控制台打印执行过程数据

        # if isinstance(profiles, PortTypeHint.Profile1D):
        #     profiles = PortTypeHint.MultiProfile1D(profile_1ds=[profiles])

        if self.liq_just_depth == 20:
            liq_just_depth = 20.0
        else:
            liq_just_depth = 15.0

        if self.seismic_intensity == "6度（0.05g）":
            seismic_intensity = '6'
        elif self.seismic_intensity == "7度（0.10g）":
            seismic_intensity = '7'
        elif self.seismic_intensity == "7度（0.15g）":
            seismic_intensity = '7.5'
        elif self.seismic_intensity == "8度（0.20g）":
            seismic_intensity = '8'
        elif self.seismic_intensity == "8度（0.30g）":
            seismic_intensity = '8.5'
        else:
            seismic_intensity = '9'

        is_special_bld = self.is_special_bld  # 是否特殊类型的建筑（对液化沉陷敏感的乙类建筑）

        if self.seismic_group == 1:
            seismic_group = 1
        elif self.seismic_group == 2:
            seismic_group = 2
        else:
            seismic_group = 3

        anti_float_water_level = self.anti_float_water_level
        f_bottom_elev = self.f_bottom_elev

        if execute_print:
            print("==计算参数")
            print("液化判别深度:", liq_just_depth)
            print("地震烈度:", seismic_intensity)
            print("是否特殊类型建筑:", is_special_bld)
            print("地震分组:", seismic_group)
            print("抗浮水位:", anti_float_water_level)
            print("基础底面标高:", f_bottom_elev)

        if seismic_intensity == "6" and is_special_bld:
            seismic_intensity = "7"

        if execute_print:
            print("\n最终使用的地震烈度:", seismic_intensity)

        layer_order_table = layer_order_tables.get_table("场地地层层序")
        layer_order_table_title_to_name = layer_order_table.title_to_name

        layer_type_data = Liquidation.get_layer_type_data(layer_order_table=layer_order_table,
                                                          layer_order_table_title_to_name=layer_order_table_title_to_name)
        all_layer_type = layer_type_data["all_layer_type"]

        if execute_print:
            print(f"\n==土类：{all_layer_type}")

        if "粉土" not in all_layer_type and "砂土" not in all_layer_type:
            print("\n==既不存在粉土，也不存在砂土，无需进行液化判断")
            self._ports_out["OutputTableCollection"].data = None
            return None

        layer_type_map = layer_type_data["layer_type_map"]
        all_layer_num = layer_type_data["all_layer_num"]

        if execute_print:
            print("\n==岩土类名相关数据：")
            print(layer_type_map)
            print(all_layer_num)

        layer_table = tables.get_table("地层表")
        layer_table_title_to_name = layer_table.title_to_name

        bore_table = tables.get_table("勘探点表")
        bore_table_title_to_name = bore_table.title_to_name

        spt_table = tables.get_table("标贯")
        spt_table_title_to_name = spt_table.title_to_name

        normal_test_table = tables.get_table("常规试验表")
        normal_test_table_title_to_name = normal_test_table.title_to_name

        if execute_print:
            print("\n==title and name")
            print(layer_order_table_title_to_name)
            print(layer_table_title_to_name)
            print(bore_table_title_to_name)
            print(spt_table_title_to_name)
            print(normal_test_table_title_to_name)

        # 标贯的样品表
        spt_data = Liquidation.get_spt_table(spt_table=spt_table,
                                             spt_table_title_to_name=spt_table_title_to_name,
                                             use_test_data=use_test_data)
        isample_material_table_spt = spt_data["isample_table_spt"]
        used_bore_id = spt_data["used_bore_id"]

        if execute_print:
            print("\n==读取到的标贯数据：")
            print("勘探点编号\t试验点顶深度\t贯入深度\t标贯击数\t样品ID")
            for i in range(len(spt_data["all_spt_arti_id"])):
                print(
                    f"{spt_data['all_bore_id'][i]}\t{spt_data['all_top_depth'][i]}\t{spt_data['all_length'][i]}\t{spt_data['all_spt_num'][i]}\t{spt_data['all_spt_arti_id'][i]}")

            print(f"\n通过标贯确定的所用钻孔: {used_bore_id}")

        # rhoc的样品表
        rhoc_data = Liquidation.get_rhoc_table(used_bore_id=used_bore_id,
                                               normal_test_table=normal_test_table,
                                               normal_test_table_title_to_name=normal_test_table_title_to_name,
                                               layer_type_map=layer_type_map,
                                               layer_table=layer_table,
                                               layer_table_title_to_name=layer_table_title_to_name,
                                               use_test_data=use_test_data)
        sample_material_table_rhoc = rhoc_data["sample_table_rhoc"]

        if len(rhoc_data["all_rhoc"]) == 0:
            print("\n==没有取到黏粒含量的数据")
            self._ports_out["OutputTableCollection"].data = None
            return None

        if execute_print:
            print("\n==读取到的黏粒含量数据：")
            print("勘探点编号\t取样顶深度\t取样长度\t取样中点深度\t黏粒含量\t样品ID")
            for i in range(len(rhoc_data["all_rhoc_arti_id"])):
                print(
                    f"{rhoc_data['all_bore_id'][i]}\t{rhoc_data['all_top_depth'][i]}\t{rhoc_data['all_length'][i]}\t{rhoc_data['all_mid_depth'][i]}\t{rhoc_data['all_rhoc'][i]}\t{rhoc_data['all_rhoc_arti_id'][i]}")

        # 材料表
        mat_data = Liquidation.get_mat_table(layer_order_table=layer_order_table,
                                             layer_order_table_title_to_name=layer_order_table_title_to_name,
                                             use_test_data=use_test_data, execute_print=execute_print)
        layer_material_table = mat_data["layer_material_table"]
        layer_num_to_id = mat_data["layer_num_to_id"]

        if execute_print:
            print("\n==地层编号到ID的映射关系:")
            for layer_num, layer_id in layer_num_to_id.items():
                print(f"地层编号: {layer_num}, ID: {layer_id}")

            print("\n==材料表中的第二项")
            print(layer_material_table.get_material(1))

        # multi profiles
        profiles = Liquidation.get_profiles(used_bore_id=used_bore_id,
                                            layer_num_to_id=layer_num_to_id,
                                            layer_table=layer_table,
                                            layer_table_title_to_name=layer_table_title_to_name,
                                            bore_table=bore_table,
                                            bore_table_title_to_name=bore_table_title_to_name,
                                            liq_just_depth=liq_just_depth,
                                            spt_data=spt_data,
                                            rhoc_data=rhoc_data,
                                            use_test_data=use_test_data,
                                            execute_print=execute_print)

        single_table_bore_id_list = []
        single_table_liq_class_list = []
        single_table_need_justify_list = []  # （报告需要）水下的粉土、砂土需要判别液化
        #
        tb1_bore_id_list = []
        tb1_layer_number_list = []
        tb1_d0_list = []
        tb1_du_list = []
        tb1_dw_list = []
        tb1_db_list = []
        tb1_rho_c_list = []
        tb1_dudw_list = []
        tb1_d0db2_list = []
        tb1_d0db3_list = []
        tb1_d0db45_list = []
        tb1_conclusion_list = []
        #
        tb2_bore_id_list = []
        tb2_layer_number_list = []
        tb2_N0_list = []
        tb2_test_depth_list = []
        tb2_dw_list = []
        tb2_rho_c_list = []
        tb2_n_cr_list = []
        tb2_n_real_list = []
        tb2_conclusion_list = []
        tb2_liq_index_list = []
        tb2_liq_reduce_factor_list = []
        for profile in profiles:  # 遍历每个钻孔
            # 基础埋深
            db = profile.top - f_bottom_elev
            if db < 2.0:
                db = 2.0
            # 地下水位深度
            dw = profile.top - anti_float_water_level
            if dw < 0.0:
                dw = 0.0
            # 钻孔名称
            profile_number = profile.pnum
            # 样品深度
            sample_depth_origin = profile.samples_depth

            du_dict = self._cal_du(profiles=profiles, material_table=layer_material_table)
            if du_dict[profile_number][0] is None:
                continue

            # 该钻孔中土层的参数
            material_id = profile.materials_id
            layer_name = []
            layer_number = []
            geo_age = []
            check_layer_mat_None = []
            for item_id in material_id:
                if layer_material_table.get_material(item_id) is None:
                    check_layer_mat_None.append(None)
            if None in check_layer_mat_None:
                continue
            for item_id in material_id:
                cur_props = layer_material_table.get_material(item_id)
                layer_name.append(cur_props[GeoMaterialProps.MaterialName])
                layer_number.append(cur_props[GeoMaterialProps.LayerNumber])
                geo_age.append(cur_props[GeoMaterialProps.GeoAge])

            # 标贯样品
            if profile.isamples_id is None:
                continue
            isample_id = profile.isamples_id
            isample_top_depth_origin = profile.isamples_top_depth
            isample_bot_depth_origin = profile.isamples_bottom_depth
            isample_center_depth_origin = profile.isamples_center_depth
            spt_number_origin = []
            check_isample_id_None = []
            for item_id in isample_id:
                if isample_material_table_spt.get_material(item_id) is None:
                    check_isample_id_None.append(None)
            if None in check_isample_id_None:
                continue
            check_spt_value_None = []
            for item_id in isample_id:
                if isample_material_table_spt.get_material(item_id)[GeoMaterialProps.SPTNumber] is None:
                    check_spt_value_None.append(None)
            if None in check_spt_value_None:
                continue
            for item_id in isample_id:
                spt_number_origin.append(isample_material_table_spt.get_material(item_id)[GeoMaterialProps.SPTNumber])

            # 黏粒样品
            if profile.samples_id is None:
                continue
            #
            sample_id = profile.samples_id
            rho_c_origin = []
            check_sample_id_None = []
            for item_id in sample_id:
                if sample_material_table_rhoc.get_material(item_id) is None:
                    check_sample_id_None.append(None)
            if None in check_sample_id_None:
                continue
            #
            for item_id in sample_id:
                cur_props = sample_material_table_rhoc.get_material(item_id)
                cur_rho_c = cur_props[GeoMaterialProps.ClayContent]
                if cur_rho_c is not None and not pd.isna(cur_rho_c):
                    rho_c_origin.append(cur_rho_c)
                # elif pd.isna(cur_rho_c):
                #     rho_c_origin.append(3.0)
                else:
                    rho_c_origin.append(3.0)

            # 原始的黏粒含量按深度对应到每个段样品上
            # sample_depth_match = []
            rho_c_match = []
            for i in range(0, len(isample_top_depth_origin)):
                cur_top_depth = isample_top_depth_origin[i]
                cur_bot_depth = isample_bot_depth_origin[i]
                tmp = 0
                for j in range(0, len(rho_c_origin)):
                    cur_sample_depth_origin = sample_depth_origin[j]
                    if (cur_top_depth - 0.2) <= cur_sample_depth_origin <= (cur_bot_depth + 0.2):
                        # sample_depth_match.append(sample_depth_origin[j])
                        rho_c_match.append(rho_c_origin[j])
                        tmp += 1
                if tmp == 0:
                    rho_c_match.append(3.0)

            # 如果一个标贯样品内含有多个黏粒含量样品
            if len(isample_id) != len(rho_c_match):
                continue

            n_layers = len(profile.layers_depth)
            layer_line_depth = [0.0]
            layer_line_depth.extend(profile.layers_depth)
            all_test_depth = []
            test_depth = [[] for _ in range(n_layers)]
            n_real = [[] for _ in range(n_layers)]
            rho_c = [[] for _ in range(n_layers)]
            for i in range(0, len(isample_center_depth_origin)):
                for j in range(0, n_layers):
                    if layer_line_depth[j] <= isample_top_depth_origin[i] <= layer_line_depth[j + 1] and \
                            layer_line_depth[j] <= isample_bot_depth_origin[i] <= layer_line_depth[j + 1] and \
                            isample_top_depth_origin[i] > dw:
                        all_test_depth.append(isample_center_depth_origin[i])
                        test_depth[j].append(isample_center_depth_origin[i])
                        n_real[j].append(spt_number_origin[i])
                        rho_c[j].append(rho_c_match[i])
            print("==== rho_c ====")
            print(rho_c)

            # 样品点中线深度
            if len(all_test_depth) < 2:
                continue
            sample_mid_depth = []
            for i in range(len(all_test_depth) - 1):
                midpoint_depth = (all_test_depth[i] + all_test_depth[i + 1]) / 2
                sample_mid_depth.append(midpoint_depth)

            # 代表土层的上下深度、代表层厚、代表层厚中点深度
            up_depth = []
            down_depth = []
            rep_thick = []
            d_mid = []
            for i in range(0, n_layers):
                cur_topline_depth = layer_line_depth[i]
                cur_botline_depth = layer_line_depth[i + 1]
                cur_up_depth = []
                cur_down_depth = []
                cur_rep_thick = []
                cur_d_mid = []
                if len(test_depth[i]) == 0:
                    up_depth.append([])
                    down_depth.append([])
                    rep_thick.append([])
                    d_mid.append([])
                    continue
                for j in range(0, len(test_depth[i])):
                    cur_test_depth = test_depth[i][j]
                    up_line_list = [cur_topline_depth]
                    if dw < cur_test_depth:
                        up_line_list.append(dw)
                    down_line_list = [cur_botline_depth]
                    if len(test_depth[i]) == 1:
                        cur_up_depth.append(float(max(up_line_list)))
                        cur_down_depth.append(float(min(down_line_list)))
                    else:
                        up_line_list_with_midline = []
                        down_line_list_with_midline = []
                        for mid_depth in sample_mid_depth:
                            if mid_depth < cur_test_depth:
                                up_line_list_with_midline.append(mid_depth)
                        for mid_depth in sample_mid_depth:
                            if mid_depth > cur_test_depth:
                                down_line_list_with_midline.append(mid_depth)
                        up_line_list_with_midline.extend(up_line_list)
                        down_line_list_with_midline.extend(down_line_list)
                        if j == 0:  # 最上面的点
                            cur_up_depth.append(float(max(up_line_list)))
                            cur_down_depth.append(float(min(down_line_list_with_midline)))
                        elif j == len(test_depth[i]) - 1:  # 最下面的点
                            cur_up_depth.append(float(max(up_line_list_with_midline)))
                            cur_down_depth.append(float(min(down_line_list)))
                        else:  # 中间的点
                            cur_up_depth.append(float(max(up_line_list_with_midline)))
                            cur_down_depth.append(float(min(down_line_list_with_midline)))
                    cur_rep_thick.append(abs(cur_up_depth[j] - cur_down_depth[j]))
                    cur_d_mid.append((cur_up_depth[j] + cur_down_depth[j]) / 2.0)
                up_depth.append(cur_up_depth)
                down_depth.append(cur_down_depth)
                rep_thick.append(cur_rep_thick)
                d_mid.append(cur_d_mid)

            sample_number = []
            for i in range(0, n_layers):
                sample_number.append(len(test_depth[i]))

            is_before_q4 = []
            for item in geo_age:
                if item == "Q4":
                    is_before_q4.append(False)
                else:
                    is_before_q4.append(True)

            soil_type = []
            all_material_names = SoilClassification["material_name"].values
            material_types = SoilClassification["for_liquidation"].values
            check_soil_class_csv_None = []
            for item in material_id:
                if layer_material_table.get_material(item) is None:
                    check_soil_class_csv_None.append(None)
            if None in check_soil_class_csv_None:
                continue
            for item in material_id:
                material_props = layer_material_table.get_material(item)
                material_name = material_props[GeoMaterialProps.MaterialName].strip()
                soil_idx = np.where(all_material_names == material_name)[0]
                if len(soil_idx) == 0:
                    material_type = "其他"
                else:
                    material_type = material_types[soil_idx[0]]
                soil_type.append(material_type)
            print("==== soil_type ====")
            print(soil_type)

            rho_c_for_liq_detail = []
            for i in range(0, len(rho_c)):
                cur_rho_c_list = rho_c[i]
                cur_soil_type = soil_type[i]
                cur_rho_c_for_liq_detail = []
                for j in range(0, len(cur_rho_c_list)):
                    if cur_soil_type == "砂土":
                        cur_rho_c_for_liq_detail.append(3.0)
                    elif cur_soil_type == "粉土":
                        if cur_rho_c_list[j] < 3.0:
                            cur_rho_c_for_liq_detail.append(3.0)
                        else:
                            cur_rho_c_for_liq_detail.append(cur_rho_c_list[j])
                    else:
                        cur_rho_c_for_liq_detail.append(cur_rho_c_list[j])
                rho_c_for_liq_detail.append(cur_rho_c_for_liq_detail)
            print("==== rho_c_for_liq_detail ====")
            print(rho_c_for_liq_detail)

            du = du_dict[profile_number][0]

            # 地层是否和地下水接触
            has_water = []
            for item in profile.layers_depth:
                if dw < item:
                    has_water.append(True)
                else:
                    has_water.append(False)

            material_id_initYesList = []  # 可能液化的地层的ID
            layer_number_initYesList = []
            d0_initYesList = []
            du_initYesList = []
            rho_c_initYesList = []
            eq1_right_initYesList = []
            eq2_right_initYesList = []
            eq3_left_initYesList = []
            eq3_right_initYesList = []
            liq_init_result_initYesList = []
            liq_init_result_str_initYesList = []
            sample_number_initYesList = []
            test_depth_initYesList = []
            rho_c_for_liq_detail_initYesList = []
            n_real_initYesList = []
            rep_thick_initYesList = []
            d_mid_initYesList = []
            soil_type_initYesList = []
            need_justify_one_bore = []
            for i in range(0, len(layer_number)):
                if has_water[i] and (soil_type[i] == "砂土" or soil_type[i] == "粉土"):
                    need_justify_one_bore.append(layer_number[i])
                    min_rho_c = min(rho_c[i]) if rho_c[i] else 3.0
                    d0, eq1_right, eq2_right, eq3_left, eq3_right, liq_init_result, liq_init_result_str = liquidationCal.liq_init_justify2(
                        seismic_intensity=str(seismic_intensity),
                        is_before_q4=is_before_q4[i], soil_type=soil_type[i],
                        rho_c=min_rho_c, du=du[i], db=db, dw=dw)
                    if liq_init_result > 0:
                        material_id_initYesList.append(material_id[i])
                        layer_number_initYesList.append(layer_number[i])
                        d0_initYesList.append(d0)
                        du_initYesList.append(du[i])
                        rho_c_initYesList.append(min_rho_c)
                        eq1_right_initYesList.append(eq1_right)
                        eq2_right_initYesList.append(eq2_right)
                        eq3_left_initYesList.append(eq3_left)
                        eq3_right_initYesList.append(eq3_right)
                        liq_init_result_initYesList.append(liq_init_result)
                        liq_init_result_str_initYesList.append(liq_init_result_str)
                        sample_number_initYesList.append(sample_number[i])
                        test_depth_initYesList.append(test_depth[i])
                        rho_c_for_liq_detail_initYesList.append(rho_c_for_liq_detail[i])
                        n_real_initYesList.append(n_real[i])
                        rep_thick_initYesList.append(rep_thick[i])
                        d_mid_initYesList.append(d_mid[i])
                        soil_type_initYesList.append(soil_type[i])

            print("==== layer_number_initYesList ====")
            print(layer_number_initYesList)
            print("==== material_id_initYesList ====")
            print(material_id_initYesList)
            sum_liq_index = 0.0
            for i in range(0, len(material_id_initYesList)):  # 详判
                if sample_number_initYesList[i] == 0:
                    tb2_bore_id_list.append(profile_number)
                    tb2_layer_number_list.append(layer_number_initYesList[i])
                    tb2_N0_list.append(0)
                    tb2_test_depth_list.append(0.0)
                    tb2_dw_list.append(0.0)
                    tb2_rho_c_list.append(0.0)
                    tb2_n_cr_list.append(0.0)
                    tb2_n_real_list.append(0)
                    tb2_conclusion_list.append("缺少标贯数据无法判断")
                    tb2_liq_index_list.append(None)
                    tb2_liq_reduce_factor_list.append(None)
                    continue
                for j in range(0, sample_number_initYesList[i]):
                    # 再判断一次黏粒含量
                    if (soil_type_initYesList[i] == "粉土"
                            and (seismic_intensity == "7" or seismic_intensity == "7.5")
                            and rho_c_for_liq_detail_initYesList[i][j] >= 10.0):
                        continue
                    elif (soil_type_initYesList[i] == "粉土"
                          and (seismic_intensity == "8" or seismic_intensity == "8.5")
                          and rho_c_for_liq_detail_initYesList[i][j] >= 13.0):
                        continue
                    elif (soil_type_initYesList[i] == "粉土"
                          and seismic_intensity == "9"
                          and rho_c_for_liq_detail_initYesList[i][j] >= 16):
                        continue
                    N0, n_cr = liquidationCal.n_cr_cal(seismic_intensity=seismic_intensity,
                                                       seismic_group=seismic_group, ds=test_depth_initYesList[i][j],
                                                       rho_c=rho_c_for_liq_detail_initYesList[i][j],
                                                       dw=dw)
                    liq_detail_result, liq_detail_result_str = liquidationCal.liq_detail_justify(
                        n_real=n_real_initYesList[i][j], n_cr=n_cr)
                    if (liq_detail_result > 0):  # 详判为液化则计算液化指数和折减系数
                        # 液化指数
                        one_liq_index = liquidationCal.one_liq_index_calc(n_real=n_real_initYesList[i][j], n_cr=n_cr,
                                                                          d=rep_thick_initYesList[i][j],
                                                                          d_mid=d_mid_initYesList[i][j])
                        sum_liq_index += one_liq_index
                        # 折减系数
                        # one_liq_reduce_factor = '1/3'
                        one_liq_reduce_factor = liquidationCal.one_liq_reduce_factor_calc(
                            n_real=n_real_initYesList[i][j],
                            n_cr=n_cr,
                            ds=test_depth_initYesList[i][j])
                        #
                        tb2_liq_index_list.append(one_liq_index)
                        tb2_liq_reduce_factor_list.append(one_liq_reduce_factor)
                    else:
                        tb2_liq_index_list.append(None)
                        tb2_liq_reduce_factor_list.append(None)

                    tb2_bore_id_list.append(profile_number)
                    tb2_layer_number_list.append(layer_number_initYesList[i])
                    tb2_N0_list.append(N0)
                    tb2_test_depth_list.append(test_depth_initYesList[i][j])
                    tb2_dw_list.append(dw)
                    tb2_rho_c_list.append(rho_c_for_liq_detail_initYesList[i][j])
                    tb2_n_cr_list.append(n_cr)
                    tb2_n_real_list.append(n_real_initYesList[i][j])
                    tb2_conclusion_list.append(liq_detail_result_str)

            liq_class = liquidationCal.liq_class_justify(sum_liq_index)

            single_table_bore_id_list.append(profile_number)
            single_table_liq_class_list.append(f"IlE={round(sum_liq_index, 2)}，液化等级{liq_class}")
            single_table_need_justify_list.append(need_justify_one_bore)
            #
            print("==== 第二次layer_number_initYesList ====")
            print(layer_number_initYesList)
            print("==== 第二次material_id_initYesList ====")
            print(material_id_initYesList)
            tb1_layer_number_list.extend(layer_number_initYesList)
            print("==== tb1_layer_number_list ====")
            print(tb1_layer_number_list)
            tb1_d0_list.extend(d0_initYesList)
            tb1_du_list.extend(du_initYesList)
            for i in range(0, len(du_initYesList)):
                tb1_dw_list.append(dw)
            for i in range(0, len(du_initYesList)):
                tb1_db_list.append(db)
            for i in range(0, len(du_initYesList)):
                tb1_bore_id_list.append(profile_number)
            tb1_rho_c_list.extend(rho_c_initYesList)
            tb1_dudw_list.extend(eq3_left_initYesList)
            tb1_d0db2_list.extend(eq1_right_initYesList)
            tb1_d0db3_list.extend(eq2_right_initYesList)
            tb1_d0db45_list.extend(eq3_right_initYesList)
            tb1_conclusion_list.extend(liq_init_result_str_initYesList)

        # 在创建DataFrame前检查，如果没有钻孔通过初判
        if not tb1_bore_id_list and single_table_bore_id_list:  # 确保有钻孔数据但都没通过初判
            # 为所有实际钻孔添加"不可能液化"结论，但保留真实计算值
            for profile in profiles:  # 重新遍历所有钻孔
                if profile.top is None:
                    continue

                profile_number = str(profile.pnum)  # 确保是字符串类型

                # 计算真实值
                db = profile.top - f_bottom_elev
                if db < 2.0:
                    db = 2.0
                dw = profile.top - anti_float_water_level
                if dw < 0.0:
                    dw = 0.0

                # 计算du，这是覆盖层厚度，可以从原始数据计算
                du_value = 0.0  # 默认值
                try:
                    # 可以从原始的du_dict中获取，或者重新计算
                    if profile_number in du_dict and du_dict[profile_number][0] is not None:
                        du_value = du_dict[profile_number][0][0] if du_dict[profile_number][0] else 0.0
                except:
                    pass

                # 添加到表中，带上真实计算值
                tb1_bore_id_list.append(profile_number)
                tb1_layer_number_list.append("全部")
                tb1_d0_list.append(0.0)  # 特征深度d0可能无法计算，使用0
                tb1_du_list.append(du_value)  # 使用真实的覆盖层厚度
                tb1_dw_list.append(dw)  # 使用真实的地下水位深度
                tb1_db_list.append(db)  # 使用真实的基础埋深
                tb1_rho_c_list.append(0.0)  # 黏粒含量可能因层而异，使用0
                tb1_dudw_list.append(du_value + dw)  # 计算du+dw的真实值
                tb1_d0db2_list.append(0.0 + db - 2.0)  # 计算d0+db-2的值
                tb1_d0db3_list.append(0.0 + db - 3.0)  # 计算d0+db-3的值
                tb1_d0db45_list.append(1.5 * 0.0 + 2.0 * db - 4.5)  # 计算1.5d0+2db-4.5的值
                tb1_conclusion_list.append("不满足液化条件")

        # 同样为表2处理，保留真实计算值
        if not tb2_bore_id_list and single_table_bore_id_list:
            for profile in profiles:
                if profile.top is None:
                    continue

                profile_number = str(profile.pnum)

                # 计算真实值
                db = profile.top - f_bottom_elev
                if db < 2.0:
                    db = 2.0
                dw = profile.top - anti_float_water_level
                if dw < 0.0:
                    dw = 0.0

                # 标贯值可能不适用于此场景，使用默认值
                tb2_bore_id_list.append(profile_number)
                tb2_layer_number_list.append("全部")
                tb2_N0_list.append(0.0)  # 基准值N0通常需要特定计算
                tb2_test_depth_list.append(0.0)  # 试验深度不适用
                tb2_dw_list.append(dw)  # 使用真实的地下水位深度
                tb2_rho_c_list.append(0.0)  # 黏粒含量可能因层而异
                tb2_n_cr_list.append(0.0)  # 临界值Ncr需要特定计算
                tb2_n_real_list.append(0.0)  # 实测值N63.5不适用
                tb2_conclusion_list.append("不满足液化条件")
                tb2_liq_index_list.append(0.0)  # 液化指数IlE为0
                tb2_liq_reduce_factor_list.append("无")  # 无折减系数

        print("==== 创建dataframe前：tb1_layer_number_list ====")
        print(tb1_layer_number_list)
        table_single_df = pd.DataFrame({GeoResults.ProfileNumber: single_table_bore_id_list,
                                        "liqClass": single_table_liq_class_list,
                                        "needJustifyLiq": single_table_need_justify_list})
        table1_multi_df = pd.DataFrame({GeoResults.ProfileNumber: tb1_bore_id_list,
                                        "layerNumber1": tb1_layer_number_list,
                                        "charaDepthD0": tb1_d0_list,
                                        "overlayThicknessDu": tb1_du_list,
                                        "UndergroundWaterDepth1": tb1_dw_list,
                                        GeoResults.FoundationDepth: tb1_db_list,
                                        "clayContentRhoc1": tb1_rho_c_list,
                                        "eq_3_left": tb1_dudw_list,
                                        "eq_1_right": tb1_d0db2_list,
                                        "eq_2_right": tb1_d0db3_list,
                                        "eq_3_right": tb1_d0db45_list,
                                        "conclusion1": tb1_conclusion_list})
        table2_multi_df = pd.DataFrame({GeoResults.ProfileNumber: tb2_bore_id_list,
                                        "layerNumber2": tb2_layer_number_list,
                                        "baseValueN0": tb2_N0_list,
                                        "testDepth": tb2_test_depth_list,
                                        "UndergroundWaterDepth2": tb2_dw_list,
                                        "clayContentRhoc2": tb2_rho_c_list,
                                        "criticalValueNcr": tb2_n_cr_list,
                                        "realValueN635": tb2_n_real_list,
                                        "conclusion2": tb2_conclusion_list,
                                        "liqIndex": tb2_liq_index_list,
                                        "liqReduceFactor": tb2_liq_reduce_factor_list})

        print("==== dataframe创建后，table1_multi_df 内容 ====")
        print(table1_multi_df)

        # 在创建DataFrame后强制统一数据类型
        table_single_df[GeoResults.ProfileNumber] = table_single_df[GeoResults.ProfileNumber].astype(str)
        table1_multi_df[GeoResults.ProfileNumber] = table1_multi_df[GeoResults.ProfileNumber].astype(str)
        table2_multi_df[GeoResults.ProfileNumber] = table2_multi_df[GeoResults.ProfileNumber].astype(str)

        single_result = TableData(table_single_df,
                                  name="single_line_table",
                                  title="单行结果表"
                                  )
        table1_result = TableData(table1_multi_df,
                                  name="multi_line_table1",
                                  title="多行结果表1"
                                  )
        table2_result = TableData(table2_multi_df,
                                  name="multi_line_table2",
                                  title="多行结果表2"
                                  )

        print("==== 创建tabledata后，table1_result 内容 ====")
        print(table1_result)

        single_result.update_field_metadata(field_name=GeoResults.ProfileNumber,
                                            title="孔号",
                                            unit=Units.UNITLESS)
        single_result.update_field_metadata(field_name="liqClass",
                                            title="液化等级",
                                            unit=Units.UNITLESS)

        table1_result.update_field_metadata(field_name=GeoResults.ProfileNumber,
                                            title="孔号",
                                            unit=Units.UNITLESS)
        table1_result.update_field_metadata(field_name="layerNumber1",
                                            title="层号",
                                            unit=Units.UNITLESS)
        table1_result.update_field_metadata(field_name="charaDepthD0",
                                            title="d0",
                                            unit=Units.m)
        table1_result.update_field_metadata(field_name="overlayThicknessDu",
                                            title="覆盖层厚度du",
                                            unit=Units.m)
        table1_result.update_field_metadata(field_name="UndergroundWaterDepth1",
                                            title="地下水位dw",
                                            unit=Units.m)
        table1_result.update_field_metadata(field_name=GeoResults.FoundationDepth,
                                            title="基础埋深db",
                                            unit=Units.m)
        table1_result.update_field_metadata(field_name="clayContentRhoc1",
                                            title="黏粒含量ρc",
                                            unit=Units.PERCENT)
        table1_result.update_field_metadata(field_name="eq_3_left",
                                            title="du+dw",
                                            unit=Units.UNITLESS)
        table1_result.update_field_metadata(field_name="eq_1_right",
                                            title="d0+db-2",
                                            unit=Units.UNITLESS)
        table1_result.update_field_metadata(field_name="eq_2_right",
                                            title="d0+db-3",
                                            unit=Units.UNITLESS)
        table1_result.update_field_metadata(field_name="eq_3_right",
                                            title="1.5d0+2db-4.5",
                                            unit=Units.UNITLESS)
        table1_result.update_field_metadata(field_name="conclusion1",
                                            title="结论",
                                            unit=Units.UNITLESS)

        table2_result.update_field_metadata(field_name=GeoResults.ProfileNumber,
                                            title="孔号",
                                            unit=Units.UNITLESS)
        table2_result.update_field_metadata(field_name="layerNumber2",
                                            title="层号",
                                            unit=Units.UNITLESS)
        table2_result.update_field_metadata(field_name="baseValueN0",
                                            title="N0",
                                            unit=Units.UNITLESS)
        table2_result.update_field_metadata(field_name="testDepth",
                                            title="试验深度",
                                            unit=Units.m)
        table2_result.update_field_metadata(field_name="UndergroundWaterDepth2",
                                            title="地下水位dw",
                                            unit=Units.m)
        table2_result.update_field_metadata(field_name="clayContentRhoc2",
                                            title="黏粒含量ρc",
                                            unit=Units.PERCENT)
        table2_result.update_field_metadata(field_name="criticalValueNcr",
                                            title="临界值Ncr",
                                            unit=Units.UNITLESS)
        table2_result.update_field_metadata(field_name="realValueN635",
                                            title="实测值N63.5",
                                            unit=Units.UNITLESS)
        table2_result.update_field_metadata(field_name="conclusion2",
                                            title="结论",
                                            unit=Units.UNITLESS)
        table2_result.update_field_metadata(field_name="liqIndex",
                                            title="液化指数IlE",
                                            unit=Units.UNITLESS)
        table2_result.update_field_metadata(field_name="liqReduceFactor",
                                            title="折减系数α",
                                            unit=Units.UNITLESS)

        output_tables = TableCollection(name="LiquidationTable", title="液化计算表")
        output_tables.add_table(single_result)
        output_tables.add_table(table1_result)
        output_tables.add_table(table2_result)

        # 分别输出单行表的数据、多行表1的数据、多行表2的数据
        print("====== 液化计算：单行表的数据、多行表1的数据、多行表2的数据 ======")
        for name in output_tables.table_names:
            table = output_tables.get_table(name)
            print(f"\n==== 表名: {table.name}，标题: {table.title} ====")
            print(table)
            # print(f"行数: {len(table._data)}，列数: {len(table._data.columns)}")
        print("====== 液化计算：单行表的数据、多行表1的数据、多行表2的数据 end ======")

        self._ports_out["OutputTableCollection"].data = output_tables

        return output_tables


@status_manage
class SeismicDesignParameters(PipeModule):
    """Get the seismis design parameters by longitude and latitude of a point based on GB 18306"""

    def __init__(self, mname: str | None = None, auto_run: bool = True,
                 token: str | None = None, host: str | None = None,
                 point: PortTypeHint.SingleResult | None = None) -> None:
        """Initialize SeismicDesignParameters object
        
        Parameters
        ----------
        point: 
            The point contains longitude and latitude
        """
        super().__init__(mname, auto_run)

        self._ports_in = {
            "InputToken": Port(ptype=PortType.Token, data=token, pdoc="The token for gdim or gbim"),
            "InputPoint": Port(ptype=PortType.SingleResult, data=point,
                               pdoc="A point defined by longitude and latitude.")
        }
        self._ports_out = {"OutputResult": Port(ptype=PortType.SingleResult, pdoc="The seismic design parameters.")}

        self.token = token
        self.host = host

    @property
    def InputPoint(self) -> None:
        raise AttributeError("Property 'InputPoint' is write-only.")

    @InputPoint.setter
    def InputPoint(self, value: PortTypeHint.SingleResult | None) -> None:
        self._ports_in["InputPoint"].data = value

    @property
    def OutputResult(self) -> PortTypeHint.SingleResult | None:
        return self._ports_out["OutputResult"].data

    def set_cal_params(self, reset: bool = True) -> None:
        return None

    def execute(self) -> PortTypeHint.SingleResult | None:
        point: PortTypeHint.SingleResult | None = self._ports_in["InputPoint"].data
        input_token: PortTypeHint.Token | None = self._ports_in["InputToken"].data

        if input_token is not None:
            self.token, _ = input_token

        if point is None or self.token is None:
            self._ports_out["OutputResult"].data = None
            return None

        # qurey epa and tg
        seismic_data = query_seismic_params_by_longitude_latitude(token=self.token,
                                                                  longitude=point[GeneralProps.Longitude].value,
                                                                  latitude=point[GeneralProps.Latitude].value,
                                                                  host=self.host)
        
        if not seismic_data["epa"] or not seismic_data["tg"]:
            warnings.warn("地震参数查询失败，请检查钻孔坐标和坐标系是否正确!", GDIDataQualityWarning)
            seismic_design_data = {"seismic_design_intensity": None, "seismic_design_group": None}
        else:
            # cal seismic design parameters
            seismic_design_data = get_seismic_design_params(epa=seismic_data["epa"], tg=seismic_data["tg"])

        seismic_intensity = UnitResult(name=GeoResults.SeismicDesignIntensity,
                                       title=GeoResults.SeismicDesignIntensity.title,
                                       value=seismic_design_data["seismic_design_intensity"])
        acceleration = UnitResult(name=GeoResults.EffectivePeakAcceleration,
                                  title=GeoResults.EffectivePeakAcceleration.title,
                                  value=seismic_data["epa"])
        group_mapping = {1: "第一组", 2: "第二组", 3: "第三组"}
        if seismic_design_data["seismic_design_group"] is not None:
            design_group = UnitResult(name=GeoResults.SeismicDesignGroup, title=GeoResults.SeismicDesignGroup.title,
                                      value=group_mapping[seismic_design_data["seismic_design_group"]])
        else:
            design_group = UnitResult(name=GeoResults.SeismicDesignGroup, title=GeoResults.SeismicDesignGroup.title,
                                      value=None)
        spectrum = UnitResult(name=GeoResults.CharacteristicPeriodOfSeismicAccelerationResponseSpectrum,
                              title=GeoResults.CharacteristicPeriodOfSeismicAccelerationResponseSpectrum.title,
                              value=seismic_data["tg"])

        # Create the Sinlge result
        output = SingleResult([acceleration, spectrum, seismic_intensity, design_group])

        self._ports_out["OutputResult"].data = output
        return output


@status_manage
class WaterSoilCorrosion(PipeModule):
    """水土腐蚀性评价"""

    def __init__(self, mname: str | None = None, auto_run: bool = True,
                 data: PortTypeHint.TableData | None = None,
                 evaluation: Literal["water", "soil"] = "water",
                 env_type: Literal["class1", "class2", "class3"] = "class1",
                 soil_type_Cl: Literal["A", "B"] = "A",
                 soil_type_PH: Literal["A", "B"] = "A",
                 water_columns_map: dict[str, str] | None = None,
                 soil_columns_map: dict[str, str] | None = None
                 ) -> None:
        """Initialize WaterSoilCorrosion object
        
        Parameters
        ----------
        data: 
            The data contains water or soil chemical analysis data.
            For water, the data unit is mg/L.
            For soil, the data unit is mg/kg.

        evaluation: 
            The evaluation type, "water" for water corrosion, "soil" for soil corrosion.

        env_type: 
            The environment type, "class1" for class1, "class2" for class2, "class3" for class3.

        soil_type_Cl: 
            The soil type for Cl, "A" for A, "B" for B.

        soil_type_PH: 
            The soil type for PH, "A" for A, "B" for B.

        water_columns_map: 
            The columns of water chemical analysis data map to the following columns. Key is the field name, value is the following name.
            - 取样编号 - GeoMaterialProps.SampleNumber
            - 氯离子含量 - GeoMaterialProps.Cl
            - 硫酸盐含量 - GeoMaterialProps.SO42 
            - 镁离子含量 - GeoMaterialProps.Mg2
            - 铵盐含量 - GeoMaterialProps.NH4
            - 苛性碱含量 - GeoMaterialProps.OH
            - 总矿化度 - GeoMaterialProps.Total.

        soil_columns_map: 
            The columns of soil chemical analysis data map to the following columns. Key is the field name, value is the following name.
            - 取样编号 - GeoMaterialProps.SampleNumber
            - 地层编号 - GeoMaterialProps.LayerNumber
            - PH值 - GeoMaterialProps.PH
            - 氯离子含量 - GeoMaterialProps.Cl
            - 硫酸盐含量 - GeoMaterialProps.SO42 
            - 镁离子含量 - GeoMaterialProps.Mg2
        """
        super().__init__(mname, auto_run)

        self._ports_in = {"InputTableData": Port(ptype=PortType.TableData, data=data,
                                                 pdoc="The data contains water or soil chemical analysis data.")}
        self._ports_out = {"OutputEnvResult": Port(ptype=PortType.TableCollection,
                                                   pdoc="The result of water or soil corrosion evaluation by environment type."),
                           "OutputClResult": Port(ptype=[PortType.TableCollection, PortType.TableData],
                                                  pdoc="The result of water or soil corrosion evaluation by Cl."),
                           "OutputPHResult": Port(ptype=PortType.TableCollection,
                                                  pdoc="The result of water or soil corrosion evaluation by PH.")}

        self.evaluation = evaluation
        self.env_type = env_type
        self.soil_type_Cl = soil_type_Cl
        self.soil_type_PH = soil_type_PH
        self.water_columns_map = water_columns_map
        self.soil_columns_map = soil_columns_map

    @property
    def InputTableData(self) -> None:
        raise AttributeError("Property 'InputTableData' is write-only.")

    @InputTableData.setter
    def InputTableData(self, value: PortTypeHint.TableData | None) -> None:
        self._ports_in["InputTableData"].data = value

    @property
    def OutputEnvResult(self) -> PortTypeHint.TableCollection | None:
        return self._ports_out["OutputEnvResult"].data

    @property
    def OutputClResult(self) -> PortTypeHint.TableCollection | PortTypeHint.TableData | None:
        return self._ports_out["OutputClResult"].data

    @property
    def OutputPHResult(self) -> PortTypeHint.TableCollection | None:
        return self._ports_out["OutputPHResult"].data

    def set_cal_params(self, reset: bool = True) -> dict[str, RangeModel]:
        return {
            "evaluation": RangeModel(vtype="str", title="评价类别", default=self.evaluation, choices=["water", "soil"]),
            "env_type": RangeModel(vtype="str", title="环境类型", default=self.env_type,
                                   choices=["class1", "class2", "class3"],
                                   choices_label=["Ⅰ类", "Ⅱ类", "Ⅲ类"]),
            "soil_type_Cl": RangeModel(vtype="str", title="土类型(Cl)", default=self.soil_type_Cl, choices=["A", "B"],
                                       choices_label=["A-地下水位以上的碎石土、砂土，稍湿的粉土，坚硬、硬塑的黏性土",
                                                      "B-湿、很湿的粉土，可塑、软塑、流塑的黏性土"]),
            "soil_type_PH": RangeModel(vtype="str", title="土类型(PH)", default=self.soil_type_PH, choices=["A", "B"],
                                       choices_label=["A-强透水土层, 碎石土和砂土", "B-弱透水土层, 粉土和黏性土"]),
            "water_columns_map": RangeModel(vtype="dict", title="水化学分析数据列映射", default=self.water_columns_map),
            "soil_columns_map": RangeModel(vtype="dict", title="土化学分析数据列映射", default=self.soil_columns_map)}

    def execute(self) -> PortTypeHint.TableCollection | PortTypeHint.TableData | None:
        table_data: PortTypeHint.TableData | None = self._ports_in["InputTableData"].data

        if table_data is None:
            self._ports_out["OutputEnvResult"].data = None
            self._ports_out["OutputClResult"].data = None
            self._ports_out["OutputPHResult"].data = None
            return None

        if self.evaluation == "water":
            if self.water_columns_map is None:
                self._ports_out["OutputEnvResult"].data = None
                self._ports_out["OutputClResult"].data = None
                self._ports_out["OutputPHResult"].data = None
                return None

            # Map the columns
            table_data = table_data.rename_columns(self.water_columns_map)
            # Evaluate by environment type
            env_result = evaluation_by_env_type(table_data, self.env_type, self.evaluation == "water")
            # Evaluate by Cl
            cl_result = concrete_corrosion_by_Cl(table_data, self.evaluation == "water", self.soil_type_Cl)

            self._ports_out["OutputEnvResult"].data = env_result
            self._ports_out["OutputClResult"].data = cl_result
            self._ports_out["OutputPHResult"].data = None

            return env_result

        elif self.evaluation == "soil":
            if self.soil_columns_map is None:
                self._ports_out["OutputEnvResult"].data = None
                self._ports_out["OutputClResult"].data = None
                self._ports_out["OutputPHResult"].data = None
                return None

            # Map the columns
            table_data = table_data.rename_columns(self.soil_columns_map)
            # Evaluate by environment type
            env_result = evaluation_by_env_type(table_data, self.env_type, self.evaluation == "water")
            # Evaluate by Cl
            cl_result = concrete_corrosion_by_Cl(table_data, self.evaluation == "water", self.soil_type_Cl)
            # Evaluate by PH
            ph_result = concrete_corrosion_by_PH(table_data, self.soil_type_PH)

            self._ports_out["OutputEnvResult"].data = env_result
            self._ports_out["OutputClResult"].data = cl_result
            self._ports_out["OutputPHResult"].data = ph_result

            return env_result

        else:
            raise ValueError(f"Invalid evaluation type {self.evaluation}.")
